1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 223547Smaybee * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <sys/zfs_context.h> 29789Sahrens #include <sys/dmu_objset.h> 30789Sahrens #include <sys/dsl_dir.h> 31789Sahrens #include <sys/dsl_dataset.h> 32789Sahrens #include <sys/dsl_prop.h> 33789Sahrens #include <sys/dsl_pool.h> 342199Sahrens #include <sys/dsl_synctask.h> 35789Sahrens #include <sys/dnode.h> 36789Sahrens #include <sys/dbuf.h> 372885Sahrens #include <sys/zvol.h> 38789Sahrens #include <sys/dmu_tx.h> 39789Sahrens #include <sys/zio_checksum.h> 40789Sahrens #include <sys/zap.h> 41789Sahrens #include <sys/zil.h> 42789Sahrens #include <sys/dmu_impl.h> 43789Sahrens 44789Sahrens 45789Sahrens spa_t * 46789Sahrens dmu_objset_spa(objset_t *os) 47789Sahrens { 48789Sahrens return (os->os->os_spa); 49789Sahrens } 50789Sahrens 51789Sahrens zilog_t * 52789Sahrens dmu_objset_zil(objset_t *os) 53789Sahrens { 54789Sahrens return (os->os->os_zil); 55789Sahrens } 56789Sahrens 57789Sahrens dsl_pool_t * 58789Sahrens dmu_objset_pool(objset_t *os) 59789Sahrens { 60789Sahrens dsl_dataset_t *ds; 61789Sahrens 62789Sahrens if ((ds = os->os->os_dsl_dataset) != NULL && ds->ds_dir) 63789Sahrens return (ds->ds_dir->dd_pool); 64789Sahrens else 65789Sahrens return (spa_get_dsl(os->os->os_spa)); 66789Sahrens } 67789Sahrens 68789Sahrens dsl_dataset_t * 69789Sahrens dmu_objset_ds(objset_t *os) 70789Sahrens { 71789Sahrens return (os->os->os_dsl_dataset); 72789Sahrens } 73789Sahrens 74789Sahrens dmu_objset_type_t 75789Sahrens dmu_objset_type(objset_t *os) 76789Sahrens { 77789Sahrens return (os->os->os_phys->os_type); 78789Sahrens } 79789Sahrens 80789Sahrens void 81789Sahrens dmu_objset_name(objset_t *os, char *buf) 82789Sahrens { 83789Sahrens dsl_dataset_name(os->os->os_dsl_dataset, buf); 84789Sahrens } 85789Sahrens 86789Sahrens uint64_t 87789Sahrens dmu_objset_id(objset_t *os) 88789Sahrens { 89789Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 90789Sahrens 91789Sahrens return (ds ? ds->ds_object : 0); 92789Sahrens } 93789Sahrens 94789Sahrens static void 95789Sahrens checksum_changed_cb(void *arg, uint64_t newval) 96789Sahrens { 97789Sahrens objset_impl_t *osi = arg; 98789Sahrens 99789Sahrens /* 100789Sahrens * Inheritance should have been done by now. 101789Sahrens */ 102789Sahrens ASSERT(newval != ZIO_CHECKSUM_INHERIT); 103789Sahrens 104789Sahrens osi->os_checksum = zio_checksum_select(newval, ZIO_CHECKSUM_ON_VALUE); 105789Sahrens } 106789Sahrens 107789Sahrens static void 108789Sahrens compression_changed_cb(void *arg, uint64_t newval) 109789Sahrens { 110789Sahrens objset_impl_t *osi = arg; 111789Sahrens 112789Sahrens /* 113789Sahrens * Inheritance and range checking should have been done by now. 114789Sahrens */ 115789Sahrens ASSERT(newval != ZIO_COMPRESS_INHERIT); 116789Sahrens 117789Sahrens osi->os_compress = zio_compress_select(newval, ZIO_COMPRESS_ON_VALUE); 118789Sahrens } 119789Sahrens 120789Sahrens void 121789Sahrens dmu_objset_byteswap(void *buf, size_t size) 122789Sahrens { 123789Sahrens objset_phys_t *osp = buf; 124789Sahrens 125789Sahrens ASSERT(size == sizeof (objset_phys_t)); 126789Sahrens dnode_byteswap(&osp->os_meta_dnode); 127789Sahrens byteswap_uint64_array(&osp->os_zil_header, sizeof (zil_header_t)); 128789Sahrens osp->os_type = BSWAP_64(osp->os_type); 129789Sahrens } 130789Sahrens 1311544Seschrock int 1321544Seschrock dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 1331544Seschrock objset_impl_t **osip) 134789Sahrens { 135789Sahrens objset_impl_t *winner, *osi; 136789Sahrens int i, err, checksum; 137789Sahrens 138789Sahrens osi = kmem_zalloc(sizeof (objset_impl_t), KM_SLEEP); 139789Sahrens osi->os.os = osi; 140789Sahrens osi->os_dsl_dataset = ds; 141789Sahrens osi->os_spa = spa; 1423547Smaybee osi->os_rootbp = bp; 1433547Smaybee if (!BP_IS_HOLE(osi->os_rootbp)) { 1442391Smaybee uint32_t aflags = ARC_WAIT; 1451544Seschrock zbookmark_t zb; 1461544Seschrock zb.zb_objset = ds ? ds->ds_object : 0; 1471544Seschrock zb.zb_object = 0; 1481544Seschrock zb.zb_level = -1; 1491544Seschrock zb.zb_blkid = 0; 1501544Seschrock 1513547Smaybee dprintf_bp(osi->os_rootbp, "reading %s", ""); 1523547Smaybee err = arc_read(NULL, spa, osi->os_rootbp, 153789Sahrens dmu_ot[DMU_OT_OBJSET].ot_byteswap, 1543547Smaybee arc_getbuf_func, &osi->os_phys_buf, 1552391Smaybee ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &aflags, &zb); 1561544Seschrock if (err) { 1571544Seschrock kmem_free(osi, sizeof (objset_impl_t)); 1581544Seschrock return (err); 1591544Seschrock } 1603547Smaybee osi->os_phys = osi->os_phys_buf->b_data; 1613547Smaybee arc_release(osi->os_phys_buf, &osi->os_phys_buf); 162789Sahrens } else { 1633547Smaybee osi->os_phys_buf = arc_buf_alloc(spa, sizeof (objset_phys_t), 1643547Smaybee &osi->os_phys_buf, ARC_BUFC_METADATA); 1653547Smaybee osi->os_phys = osi->os_phys_buf->b_data; 166789Sahrens bzero(osi->os_phys, sizeof (objset_phys_t)); 167789Sahrens } 168789Sahrens 169789Sahrens /* 170789Sahrens * Note: the changed_cb will be called once before the register 171789Sahrens * func returns, thus changing the checksum/compression from the 1722082Seschrock * default (fletcher2/off). Snapshots don't need to know, and 1732082Seschrock * registering would complicate clone promotion. 174789Sahrens */ 1752082Seschrock if (ds && ds->ds_phys->ds_num_children == 0) { 176789Sahrens err = dsl_prop_register(ds, "checksum", 177789Sahrens checksum_changed_cb, osi); 1781544Seschrock if (err == 0) 1791544Seschrock err = dsl_prop_register(ds, "compression", 1801544Seschrock compression_changed_cb, osi); 1811544Seschrock if (err) { 1823547Smaybee VERIFY(arc_buf_remove_ref(osi->os_phys_buf, 1833547Smaybee &osi->os_phys_buf) == 1); 1841544Seschrock kmem_free(osi, sizeof (objset_impl_t)); 1851544Seschrock return (err); 1861544Seschrock } 1872082Seschrock } else if (ds == NULL) { 188789Sahrens /* It's the meta-objset. */ 189789Sahrens osi->os_checksum = ZIO_CHECKSUM_FLETCHER_4; 1901544Seschrock osi->os_compress = ZIO_COMPRESS_LZJB; 191789Sahrens } 192789Sahrens 1931544Seschrock osi->os_zil = zil_alloc(&osi->os, &osi->os_phys->os_zil_header); 1941544Seschrock 195789Sahrens /* 196789Sahrens * Metadata always gets compressed and checksummed. 197789Sahrens * If the data checksum is multi-bit correctable, and it's not 198789Sahrens * a ZBT-style checksum, then it's suitable for metadata as well. 199789Sahrens * Otherwise, the metadata checksum defaults to fletcher4. 200789Sahrens */ 201789Sahrens checksum = osi->os_checksum; 202789Sahrens 203789Sahrens if (zio_checksum_table[checksum].ci_correctable && 204789Sahrens !zio_checksum_table[checksum].ci_zbt) 205789Sahrens osi->os_md_checksum = checksum; 206789Sahrens else 207789Sahrens osi->os_md_checksum = ZIO_CHECKSUM_FLETCHER_4; 2081544Seschrock osi->os_md_compress = ZIO_COMPRESS_LZJB; 209789Sahrens 210789Sahrens for (i = 0; i < TXG_SIZE; i++) { 211789Sahrens list_create(&osi->os_dirty_dnodes[i], sizeof (dnode_t), 212789Sahrens offsetof(dnode_t, dn_dirty_link[i])); 213789Sahrens list_create(&osi->os_free_dnodes[i], sizeof (dnode_t), 214789Sahrens offsetof(dnode_t, dn_dirty_link[i])); 215789Sahrens } 216789Sahrens list_create(&osi->os_dnodes, sizeof (dnode_t), 217789Sahrens offsetof(dnode_t, dn_link)); 218789Sahrens list_create(&osi->os_downgraded_dbufs, sizeof (dmu_buf_impl_t), 219789Sahrens offsetof(dmu_buf_impl_t, db_link)); 220789Sahrens 2212856Snd150628 mutex_init(&osi->os_lock, NULL, MUTEX_DEFAULT, NULL); 2222856Snd150628 mutex_init(&osi->os_obj_lock, NULL, MUTEX_DEFAULT, NULL); 2232856Snd150628 224789Sahrens osi->os_meta_dnode = dnode_special_open(osi, 225789Sahrens &osi->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT); 226789Sahrens 227789Sahrens if (ds != NULL) { 228789Sahrens winner = dsl_dataset_set_user_ptr(ds, osi, dmu_objset_evict); 229789Sahrens if (winner) { 230789Sahrens dmu_objset_evict(ds, osi); 231789Sahrens osi = winner; 232789Sahrens } 233789Sahrens } 234789Sahrens 2351544Seschrock *osip = osi; 2361544Seschrock return (0); 237789Sahrens } 238789Sahrens 239789Sahrens /* called from zpl */ 240789Sahrens int 241789Sahrens dmu_objset_open(const char *name, dmu_objset_type_t type, int mode, 242789Sahrens objset_t **osp) 243789Sahrens { 244789Sahrens dsl_dataset_t *ds; 245789Sahrens int err; 246789Sahrens objset_t *os; 247789Sahrens objset_impl_t *osi; 248789Sahrens 249789Sahrens os = kmem_alloc(sizeof (objset_t), KM_SLEEP); 250789Sahrens err = dsl_dataset_open(name, mode, os, &ds); 251789Sahrens if (err) { 252789Sahrens kmem_free(os, sizeof (objset_t)); 253789Sahrens return (err); 254789Sahrens } 255789Sahrens 256789Sahrens osi = dsl_dataset_get_user_ptr(ds); 257789Sahrens if (osi == NULL) { 2581544Seschrock err = dmu_objset_open_impl(dsl_dataset_get_spa(ds), 2593547Smaybee ds, &ds->ds_phys->ds_bp, &osi); 2601544Seschrock if (err) { 2611544Seschrock dsl_dataset_close(ds, mode, os); 2621544Seschrock kmem_free(os, sizeof (objset_t)); 2631544Seschrock return (err); 2641544Seschrock } 265789Sahrens } 266789Sahrens 267789Sahrens os->os = osi; 268789Sahrens os->os_mode = mode; 269789Sahrens 270789Sahrens if (type != DMU_OST_ANY && type != os->os->os_phys->os_type) { 271789Sahrens dmu_objset_close(os); 272789Sahrens return (EINVAL); 273789Sahrens } 274789Sahrens *osp = os; 275789Sahrens return (0); 276789Sahrens } 277789Sahrens 278789Sahrens void 279789Sahrens dmu_objset_close(objset_t *os) 280789Sahrens { 281789Sahrens dsl_dataset_close(os->os->os_dsl_dataset, os->os_mode, os); 282789Sahrens kmem_free(os, sizeof (objset_t)); 283789Sahrens } 284789Sahrens 2851646Sperrin int 2861646Sperrin dmu_objset_evict_dbufs(objset_t *os, int try) 2871544Seschrock { 2881544Seschrock objset_impl_t *osi = os->os; 2891544Seschrock dnode_t *dn; 2901596Sahrens 2911596Sahrens mutex_enter(&osi->os_lock); 2921596Sahrens 2931596Sahrens /* process the mdn last, since the other dnodes have holds on it */ 2941596Sahrens list_remove(&osi->os_dnodes, osi->os_meta_dnode); 2951596Sahrens list_insert_tail(&osi->os_dnodes, osi->os_meta_dnode); 2961544Seschrock 2971544Seschrock /* 2981596Sahrens * Find the first dnode with holds. We have to do this dance 2991596Sahrens * because dnode_add_ref() only works if you already have a 3001596Sahrens * hold. If there are no holds then it has no dbufs so OK to 3011596Sahrens * skip. 3021544Seschrock */ 3031596Sahrens for (dn = list_head(&osi->os_dnodes); 3041596Sahrens dn && refcount_is_zero(&dn->dn_holds); 3051596Sahrens dn = list_next(&osi->os_dnodes, dn)) 3061596Sahrens continue; 3071596Sahrens if (dn) 3081596Sahrens dnode_add_ref(dn, FTAG); 3091596Sahrens 3101596Sahrens while (dn) { 3111596Sahrens dnode_t *next_dn = dn; 3121596Sahrens 3131596Sahrens do { 3141596Sahrens next_dn = list_next(&osi->os_dnodes, next_dn); 3151596Sahrens } while (next_dn && refcount_is_zero(&next_dn->dn_holds)); 3161596Sahrens if (next_dn) 3171596Sahrens dnode_add_ref(next_dn, FTAG); 3181596Sahrens 3191596Sahrens mutex_exit(&osi->os_lock); 3201646Sperrin if (dnode_evict_dbufs(dn, try)) { 3211646Sperrin dnode_rele(dn, FTAG); 3221646Sperrin if (next_dn) 3231646Sperrin dnode_rele(next_dn, FTAG); 3241646Sperrin return (1); 3251646Sperrin } 3261596Sahrens dnode_rele(dn, FTAG); 3271596Sahrens mutex_enter(&osi->os_lock); 3281596Sahrens dn = next_dn; 3291544Seschrock } 3301544Seschrock mutex_exit(&osi->os_lock); 3311646Sperrin return (0); 3321544Seschrock } 3331544Seschrock 3341544Seschrock void 335789Sahrens dmu_objset_evict(dsl_dataset_t *ds, void *arg) 336789Sahrens { 337789Sahrens objset_impl_t *osi = arg; 3381544Seschrock objset_t os; 3392082Seschrock int i; 340789Sahrens 341789Sahrens for (i = 0; i < TXG_SIZE; i++) { 342789Sahrens ASSERT(list_head(&osi->os_dirty_dnodes[i]) == NULL); 343789Sahrens ASSERT(list_head(&osi->os_free_dnodes[i]) == NULL); 344789Sahrens } 345789Sahrens 3462082Seschrock if (ds && ds->ds_phys->ds_num_children == 0) { 3472082Seschrock VERIFY(0 == dsl_prop_unregister(ds, "checksum", 3482082Seschrock checksum_changed_cb, osi)); 3492082Seschrock VERIFY(0 == dsl_prop_unregister(ds, "compression", 3502082Seschrock compression_changed_cb, osi)); 351789Sahrens } 352789Sahrens 3531544Seschrock /* 3541544Seschrock * We should need only a single pass over the dnode list, since 3551544Seschrock * nothing can be added to the list at this point. 3561544Seschrock */ 3571544Seschrock os.os = osi; 3581646Sperrin (void) dmu_objset_evict_dbufs(&os, 0); 3591544Seschrock 360789Sahrens ASSERT3P(list_head(&osi->os_dnodes), ==, osi->os_meta_dnode); 361789Sahrens ASSERT3P(list_tail(&osi->os_dnodes), ==, osi->os_meta_dnode); 362789Sahrens ASSERT3P(list_head(&osi->os_meta_dnode->dn_dbufs), ==, NULL); 363789Sahrens 364789Sahrens dnode_special_close(osi->os_meta_dnode); 365789Sahrens zil_free(osi->os_zil); 366789Sahrens 3673547Smaybee VERIFY(arc_buf_remove_ref(osi->os_phys_buf, &osi->os_phys_buf) == 1); 3682856Snd150628 mutex_destroy(&osi->os_lock); 3692856Snd150628 mutex_destroy(&osi->os_obj_lock); 370789Sahrens kmem_free(osi, sizeof (objset_impl_t)); 371789Sahrens } 372789Sahrens 373789Sahrens /* called from dsl for meta-objset */ 374789Sahrens objset_impl_t * 3753547Smaybee dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 3763547Smaybee dmu_objset_type_t type, dmu_tx_t *tx) 377789Sahrens { 378789Sahrens objset_impl_t *osi; 379789Sahrens dnode_t *mdn; 380789Sahrens 381789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 3823547Smaybee VERIFY(0 == dmu_objset_open_impl(spa, ds, bp, &osi)); 383789Sahrens mdn = osi->os_meta_dnode; 384789Sahrens 385789Sahrens dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT, 386789Sahrens DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx); 387789Sahrens 388789Sahrens /* 389789Sahrens * We don't want to have to increase the meta-dnode's nlevels 390789Sahrens * later, because then we could do it in quescing context while 391789Sahrens * we are also accessing it in open context. 392789Sahrens * 393789Sahrens * This precaution is not necessary for the MOS (ds == NULL), 394789Sahrens * because the MOS is only updated in syncing context. 395789Sahrens * This is most fortunate: the MOS is the only objset that 396789Sahrens * needs to be synced multiple times as spa_sync() iterates 397789Sahrens * to convergence, so minimizing its dn_nlevels matters. 398789Sahrens */ 3991544Seschrock if (ds != NULL) { 4001544Seschrock int levels = 1; 4011544Seschrock 4021544Seschrock /* 4031544Seschrock * Determine the number of levels necessary for the meta-dnode 4041544Seschrock * to contain DN_MAX_OBJECT dnodes. 4051544Seschrock */ 4061544Seschrock while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift + 4071544Seschrock (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) < 4081544Seschrock DN_MAX_OBJECT * sizeof (dnode_phys_t)) 4091544Seschrock levels++; 4101544Seschrock 411789Sahrens mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = 4121544Seschrock mdn->dn_nlevels = levels; 4131544Seschrock } 414789Sahrens 415789Sahrens ASSERT(type != DMU_OST_NONE); 416789Sahrens ASSERT(type != DMU_OST_ANY); 417789Sahrens ASSERT(type < DMU_OST_NUMTYPES); 418789Sahrens osi->os_phys->os_type = type; 419789Sahrens 420789Sahrens dsl_dataset_dirty(ds, tx); 421789Sahrens 422789Sahrens return (osi); 423789Sahrens } 424789Sahrens 425789Sahrens struct oscarg { 426789Sahrens void (*userfunc)(objset_t *os, void *arg, dmu_tx_t *tx); 427789Sahrens void *userarg; 428789Sahrens dsl_dataset_t *clone_parent; 429789Sahrens const char *lastname; 430789Sahrens dmu_objset_type_t type; 431789Sahrens }; 432789Sahrens 4332199Sahrens /* ARGSUSED */ 434789Sahrens static int 4352199Sahrens dmu_objset_create_check(void *arg1, void *arg2, dmu_tx_t *tx) 436789Sahrens { 4372199Sahrens dsl_dir_t *dd = arg1; 4382199Sahrens struct oscarg *oa = arg2; 4392199Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 4402199Sahrens int err; 4412199Sahrens uint64_t ddobj; 4422199Sahrens 4432199Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 4442199Sahrens oa->lastname, sizeof (uint64_t), 1, &ddobj); 4452199Sahrens if (err != ENOENT) 4462199Sahrens return (err ? err : EEXIST); 4472199Sahrens 4482199Sahrens if (oa->clone_parent != NULL) { 4492199Sahrens /* 4502199Sahrens * You can't clone across pools. 4512199Sahrens */ 4522199Sahrens if (oa->clone_parent->ds_dir->dd_pool != dd->dd_pool) 4532199Sahrens return (EXDEV); 4542199Sahrens 4552199Sahrens /* 4562199Sahrens * You can only clone snapshots, not the head datasets. 4572199Sahrens */ 4582199Sahrens if (oa->clone_parent->ds_phys->ds_num_children == 0) 4592199Sahrens return (EINVAL); 4602199Sahrens } 4612199Sahrens return (0); 4622199Sahrens } 4632199Sahrens 4642199Sahrens static void 4652199Sahrens dmu_objset_create_sync(void *arg1, void *arg2, dmu_tx_t *tx) 4662199Sahrens { 4672199Sahrens dsl_dir_t *dd = arg1; 4682199Sahrens struct oscarg *oa = arg2; 469789Sahrens dsl_dataset_t *ds; 4703547Smaybee blkptr_t *bp; 4712199Sahrens uint64_t dsobj; 472789Sahrens 473789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 474789Sahrens 4752199Sahrens dsobj = dsl_dataset_create_sync(dd, oa->lastname, 476789Sahrens oa->clone_parent, tx); 477789Sahrens 4782199Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 4791544Seschrock DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ds)); 4803547Smaybee bp = dsl_dataset_get_blkptr(ds); 4813547Smaybee if (BP_IS_HOLE(bp)) { 482789Sahrens objset_impl_t *osi; 483789Sahrens 484789Sahrens /* This is an empty dmu_objset; not a clone. */ 485789Sahrens osi = dmu_objset_create_impl(dsl_dataset_get_spa(ds), 4863547Smaybee ds, bp, oa->type, tx); 487789Sahrens 488789Sahrens if (oa->userfunc) 489789Sahrens oa->userfunc(&osi->os, oa->userarg, tx); 490789Sahrens } 491789Sahrens dsl_dataset_close(ds, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG); 492789Sahrens } 493789Sahrens 494789Sahrens int 495789Sahrens dmu_objset_create(const char *name, dmu_objset_type_t type, 496789Sahrens objset_t *clone_parent, 497789Sahrens void (*func)(objset_t *os, void *arg, dmu_tx_t *tx), void *arg) 498789Sahrens { 4992199Sahrens dsl_dir_t *pdd; 500789Sahrens const char *tail; 501789Sahrens int err = 0; 5022199Sahrens struct oscarg oa = { 0 }; 503789Sahrens 5042199Sahrens ASSERT(strchr(name, '@') == NULL); 5052199Sahrens err = dsl_dir_open(name, FTAG, &pdd, &tail); 5061544Seschrock if (err) 5071544Seschrock return (err); 508789Sahrens if (tail == NULL) { 5092199Sahrens dsl_dir_close(pdd, FTAG); 510789Sahrens return (EEXIST); 511789Sahrens } 512789Sahrens 513789Sahrens dprintf("name=%s\n", name); 514789Sahrens 5152199Sahrens oa.userfunc = func; 5162199Sahrens oa.userarg = arg; 5172199Sahrens oa.lastname = tail; 5182199Sahrens oa.type = type; 5192199Sahrens if (clone_parent != NULL) { 520789Sahrens /* 5212199Sahrens * You can't clone to a different type. 522789Sahrens */ 5232199Sahrens if (clone_parent->os->os_phys->os_type != type) { 5242199Sahrens dsl_dir_close(pdd, FTAG); 5252199Sahrens return (EINVAL); 526789Sahrens } 5272199Sahrens oa.clone_parent = clone_parent->os->os_dsl_dataset; 528789Sahrens } 5292199Sahrens err = dsl_sync_task_do(pdd->dd_pool, dmu_objset_create_check, 5302199Sahrens dmu_objset_create_sync, pdd, &oa, 5); 5312199Sahrens dsl_dir_close(pdd, FTAG); 532789Sahrens return (err); 533789Sahrens } 534789Sahrens 535789Sahrens int 536789Sahrens dmu_objset_destroy(const char *name) 537789Sahrens { 538789Sahrens objset_t *os; 539789Sahrens int error; 540789Sahrens 541789Sahrens /* 542789Sahrens * If it looks like we'll be able to destroy it, and there's 543789Sahrens * an unplayed replay log sitting around, destroy the log. 544789Sahrens * It would be nicer to do this in dsl_dataset_destroy_sync(), 545789Sahrens * but the replay log objset is modified in open context. 546789Sahrens */ 547789Sahrens error = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 548789Sahrens if (error == 0) { 5491807Sbonwick zil_destroy(dmu_objset_zil(os), B_FALSE); 550789Sahrens dmu_objset_close(os); 551789Sahrens } 552789Sahrens 553789Sahrens return (dsl_dataset_destroy(name)); 554789Sahrens } 555789Sahrens 556789Sahrens int 557789Sahrens dmu_objset_rollback(const char *name) 558789Sahrens { 559789Sahrens int err; 560789Sahrens objset_t *os; 561789Sahrens 5622199Sahrens err = dmu_objset_open(name, DMU_OST_ANY, 5632199Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); 564789Sahrens if (err == 0) { 565789Sahrens err = zil_suspend(dmu_objset_zil(os)); 566789Sahrens if (err == 0) 567789Sahrens zil_resume(dmu_objset_zil(os)); 568789Sahrens if (err == 0) { 569789Sahrens /* XXX uncache everything? */ 5702199Sahrens err = dsl_dataset_rollback(os->os->os_dsl_dataset); 571789Sahrens } 5722199Sahrens dmu_objset_close(os); 573789Sahrens } 574789Sahrens return (err); 575789Sahrens } 576789Sahrens 5772199Sahrens struct snaparg { 5782199Sahrens dsl_sync_task_group_t *dstg; 5792199Sahrens char *snapname; 5802199Sahrens char failed[MAXPATHLEN]; 5812199Sahrens }; 5822199Sahrens 5832199Sahrens static int 5842199Sahrens dmu_objset_snapshot_one(char *name, void *arg) 5852199Sahrens { 5862199Sahrens struct snaparg *sn = arg; 5872199Sahrens objset_t *os; 5883637Srm160521 dmu_objset_stats_t stat; 5892199Sahrens int err; 5902199Sahrens 5912199Sahrens (void) strcpy(sn->failed, name); 5922199Sahrens 5932199Sahrens err = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_STANDARD, &os); 5942199Sahrens if (err != 0) 5952199Sahrens return (err); 5962199Sahrens 5972199Sahrens /* 5983637Srm160521 * If the objset is in an inconsistent state, return busy. 5993637Srm160521 */ 6003637Srm160521 dmu_objset_fast_stat(os, &stat); 6013637Srm160521 if (stat.dds_inconsistent) { 6023637Srm160521 dmu_objset_close(os); 6033637Srm160521 return (EBUSY); 6043637Srm160521 } 6053637Srm160521 6063637Srm160521 /* 6072199Sahrens * NB: we need to wait for all in-flight changes to get to disk, 6082199Sahrens * so that we snapshot those changes. zil_suspend does this as 6092199Sahrens * a side effect. 6102199Sahrens */ 6112199Sahrens err = zil_suspend(dmu_objset_zil(os)); 6122199Sahrens if (err == 0) { 6132199Sahrens dsl_sync_task_create(sn->dstg, dsl_dataset_snapshot_check, 6142199Sahrens dsl_dataset_snapshot_sync, os, sn->snapname, 3); 6153637Srm160521 } else { 6163637Srm160521 dmu_objset_close(os); 6172199Sahrens } 6183637Srm160521 6192199Sahrens return (err); 6202199Sahrens } 6212199Sahrens 6222199Sahrens int 6232199Sahrens dmu_objset_snapshot(char *fsname, char *snapname, boolean_t recursive) 6242199Sahrens { 6252199Sahrens dsl_sync_task_t *dst; 6262199Sahrens struct snaparg sn = { 0 }; 6272199Sahrens char *cp; 6282199Sahrens spa_t *spa; 6292199Sahrens int err; 6302199Sahrens 6312199Sahrens (void) strcpy(sn.failed, fsname); 6322199Sahrens 6332199Sahrens cp = strchr(fsname, '/'); 6342199Sahrens if (cp) { 6352199Sahrens *cp = '\0'; 6362199Sahrens err = spa_open(fsname, &spa, FTAG); 6372199Sahrens *cp = '/'; 6382199Sahrens } else { 6392199Sahrens err = spa_open(fsname, &spa, FTAG); 6402199Sahrens } 6412199Sahrens if (err) 6422199Sahrens return (err); 6432199Sahrens 6442199Sahrens sn.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 6452199Sahrens sn.snapname = snapname; 6462199Sahrens 6472417Sahrens if (recursive) { 6482417Sahrens err = dmu_objset_find(fsname, 6492417Sahrens dmu_objset_snapshot_one, &sn, DS_FIND_CHILDREN); 6502417Sahrens } else { 6512199Sahrens err = dmu_objset_snapshot_one(fsname, &sn); 6522417Sahrens } 6532199Sahrens 6542199Sahrens if (err) 6552199Sahrens goto out; 6562199Sahrens 6572199Sahrens err = dsl_sync_task_group_wait(sn.dstg); 6582199Sahrens 6592199Sahrens for (dst = list_head(&sn.dstg->dstg_tasks); dst; 6602199Sahrens dst = list_next(&sn.dstg->dstg_tasks, dst)) { 6612199Sahrens objset_t *os = dst->dst_arg1; 6622199Sahrens if (dst->dst_err) 6632199Sahrens dmu_objset_name(os, sn.failed); 6642199Sahrens zil_resume(dmu_objset_zil(os)); 6652199Sahrens dmu_objset_close(os); 6662199Sahrens } 6672199Sahrens out: 6682199Sahrens if (err) 6692199Sahrens (void) strcpy(fsname, sn.failed); 6702199Sahrens dsl_sync_task_group_destroy(sn.dstg); 6712199Sahrens spa_close(spa, FTAG); 6722199Sahrens return (err); 6732199Sahrens } 6742199Sahrens 675789Sahrens static void 6763547Smaybee dmu_objset_sync_dnodes(list_t *list, dmu_tx_t *tx) 677789Sahrens { 6783547Smaybee dnode_t *dn; 679789Sahrens 6803547Smaybee while (dn = list_head(list)) { 6813547Smaybee ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT); 6823547Smaybee ASSERT(dn->dn_dbuf->db_data_pending); 6833547Smaybee /* 6843547Smaybee * Initialize dn_zio outside dnode_sync() 6853547Smaybee * to accomodate meta-dnode 6863547Smaybee */ 6873547Smaybee dn->dn_zio = dn->dn_dbuf->db_data_pending->dr_zio; 6883547Smaybee ASSERT(dn->dn_zio); 689789Sahrens 6903547Smaybee ASSERT3U(dn->dn_nlevels, <=, DN_MAX_LEVELS); 6913547Smaybee list_remove(list, dn); 6923547Smaybee dnode_sync(dn, tx); 6933547Smaybee } 6943547Smaybee } 6952981Sahrens 6963547Smaybee /* ARGSUSED */ 6973547Smaybee static void 6983547Smaybee ready(zio_t *zio, arc_buf_t *abuf, void *arg) 6993547Smaybee { 7003547Smaybee objset_impl_t *os = arg; 7013547Smaybee blkptr_t *bp = os->os_rootbp; 7023547Smaybee dnode_phys_t *dnp = &os->os_phys->os_meta_dnode; 7033547Smaybee int i; 7042981Sahrens 7053547Smaybee /* 7063547Smaybee * Update rootbp fill count. 7073547Smaybee */ 7083547Smaybee bp->blk_fill = 1; /* count the meta-dnode */ 7093547Smaybee for (i = 0; i < dnp->dn_nblkptr; i++) 7103547Smaybee bp->blk_fill += dnp->dn_blkptr[i].blk_fill; 711789Sahrens } 712789Sahrens 713789Sahrens /* ARGSUSED */ 714789Sahrens static void 715789Sahrens killer(zio_t *zio, arc_buf_t *abuf, void *arg) 716789Sahrens { 717789Sahrens objset_impl_t *os = arg; 718789Sahrens 719789Sahrens ASSERT3U(zio->io_error, ==, 0); 720789Sahrens 721789Sahrens BP_SET_TYPE(zio->io_bp, DMU_OT_OBJSET); 722789Sahrens BP_SET_LEVEL(zio->io_bp, 0); 723789Sahrens 724789Sahrens if (!DVA_EQUAL(BP_IDENTITY(zio->io_bp), 725789Sahrens BP_IDENTITY(&zio->io_bp_orig))) { 7263547Smaybee if (zio->io_bp_orig.blk_birth == os->os_synctx->tx_txg) 7273547Smaybee dsl_dataset_block_kill(os->os_dsl_dataset, 7283547Smaybee &zio->io_bp_orig, NULL, os->os_synctx); 729789Sahrens dsl_dataset_block_born(os->os_dsl_dataset, zio->io_bp, 730789Sahrens os->os_synctx); 731789Sahrens } 7323547Smaybee arc_release(os->os_phys_buf, &os->os_phys_buf); 7333547Smaybee 7343547Smaybee if (os->os_dsl_dataset) 7353547Smaybee dmu_buf_rele(os->os_dsl_dataset->ds_dbuf, os->os_dsl_dataset); 736789Sahrens } 737789Sahrens 738789Sahrens /* called from dsl */ 739789Sahrens void 7403547Smaybee dmu_objset_sync(objset_impl_t *os, zio_t *pio, dmu_tx_t *tx) 741789Sahrens { 742789Sahrens int txgoff; 7431544Seschrock zbookmark_t zb; 7443547Smaybee zio_t *zio; 7453547Smaybee list_t *list; 7463547Smaybee dbuf_dirty_record_t *dr; 747*3689Sek110237 int zio_flags; 7483547Smaybee 7493547Smaybee dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg); 750789Sahrens 751789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 752789Sahrens /* XXX the write_done callback should really give us the tx... */ 753789Sahrens os->os_synctx = tx; 754789Sahrens 7553547Smaybee /* 7563547Smaybee * Create the root block IO 7573547Smaybee */ 7583547Smaybee zb.zb_objset = os->os_dsl_dataset ? os->os_dsl_dataset->ds_object : 0; 7593547Smaybee zb.zb_object = 0; 7603547Smaybee zb.zb_level = -1; 7613547Smaybee zb.zb_blkid = 0; 762*3689Sek110237 zio_flags = ZIO_FLAG_MUSTSUCCEED; 763*3689Sek110237 if (dmu_ot[DMU_OT_OBJSET].ot_metadata || zb.zb_level != 0) 764*3689Sek110237 zio_flags |= ZIO_FLAG_METADATA; 7653547Smaybee if (BP_IS_OLDER(os->os_rootbp, tx->tx_txg)) 7663547Smaybee dsl_dataset_block_kill(os->os_dsl_dataset, 7673547Smaybee os->os_rootbp, pio, tx); 7683547Smaybee zio = arc_write(pio, os->os_spa, os->os_md_checksum, 7693547Smaybee os->os_md_compress, 7703547Smaybee dmu_get_replication_level(os->os_spa, &zb, DMU_OT_OBJSET), 7713547Smaybee tx->tx_txg, os->os_rootbp, os->os_phys_buf, ready, killer, os, 772*3689Sek110237 ZIO_PRIORITY_ASYNC_WRITE, zio_flags, &zb); 7733547Smaybee 7743547Smaybee /* 7753547Smaybee * Sync meta-dnode - the parent IO for the sync is the root block 7763547Smaybee */ 7773547Smaybee os->os_meta_dnode->dn_zio = zio; 7783547Smaybee dnode_sync(os->os_meta_dnode, tx); 779789Sahrens 780789Sahrens txgoff = tx->tx_txg & TXG_MASK; 781789Sahrens 7823547Smaybee dmu_objset_sync_dnodes(&os->os_free_dnodes[txgoff], tx); 7833547Smaybee dmu_objset_sync_dnodes(&os->os_dirty_dnodes[txgoff], tx); 784789Sahrens 7853547Smaybee list = &os->os_meta_dnode->dn_dirty_records[txgoff]; 7863547Smaybee while (dr = list_head(list)) { 7873547Smaybee ASSERT(dr->dr_dbuf->db_level == 0); 7883547Smaybee list_remove(list, dr); 7893547Smaybee if (dr->dr_zio) 7903547Smaybee zio_nowait(dr->dr_zio); 7913547Smaybee } 792789Sahrens /* 793789Sahrens * Free intent log blocks up to this tx. 794789Sahrens */ 795789Sahrens zil_sync(os->os_zil, tx); 7963547Smaybee zio_nowait(zio); 797789Sahrens } 798789Sahrens 799789Sahrens void 8002885Sahrens dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp, 8012885Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 8022885Sahrens { 8032885Sahrens dsl_dataset_space(os->os->os_dsl_dataset, refdbytesp, availbytesp, 8042885Sahrens usedobjsp, availobjsp); 8052885Sahrens } 8062885Sahrens 8072885Sahrens uint64_t 8082885Sahrens dmu_objset_fsid_guid(objset_t *os) 8092885Sahrens { 8102885Sahrens return (dsl_dataset_fsid_guid(os->os->os_dsl_dataset)); 8112885Sahrens } 8122885Sahrens 8132885Sahrens void 8142885Sahrens dmu_objset_fast_stat(objset_t *os, dmu_objset_stats_t *stat) 815789Sahrens { 8162885Sahrens stat->dds_type = os->os->os_phys->os_type; 8172885Sahrens if (os->os->os_dsl_dataset) 8182885Sahrens dsl_dataset_fast_stat(os->os->os_dsl_dataset, stat); 8192885Sahrens } 8202885Sahrens 8212885Sahrens void 8222885Sahrens dmu_objset_stats(objset_t *os, nvlist_t *nv) 8232885Sahrens { 8242885Sahrens ASSERT(os->os->os_dsl_dataset || 8252885Sahrens os->os->os_phys->os_type == DMU_OST_META); 8262885Sahrens 8272885Sahrens if (os->os->os_dsl_dataset != NULL) 8282885Sahrens dsl_dataset_stats(os->os->os_dsl_dataset, nv); 8292885Sahrens 8302885Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_TYPE, 8312885Sahrens os->os->os_phys->os_type); 832789Sahrens } 833789Sahrens 834789Sahrens int 835789Sahrens dmu_objset_is_snapshot(objset_t *os) 836789Sahrens { 837789Sahrens if (os->os->os_dsl_dataset != NULL) 838789Sahrens return (dsl_dataset_is_snapshot(os->os->os_dsl_dataset)); 839789Sahrens else 840789Sahrens return (B_FALSE); 841789Sahrens } 842789Sahrens 843789Sahrens int 844789Sahrens dmu_snapshot_list_next(objset_t *os, int namelen, char *name, 845885Sahrens uint64_t *idp, uint64_t *offp) 846789Sahrens { 847789Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 848789Sahrens zap_cursor_t cursor; 849789Sahrens zap_attribute_t attr; 850789Sahrens 851789Sahrens if (ds->ds_phys->ds_snapnames_zapobj == 0) 852789Sahrens return (ENOENT); 853789Sahrens 854789Sahrens zap_cursor_init_serialized(&cursor, 855789Sahrens ds->ds_dir->dd_pool->dp_meta_objset, 856789Sahrens ds->ds_phys->ds_snapnames_zapobj, *offp); 857789Sahrens 858885Sahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 859885Sahrens zap_cursor_fini(&cursor); 860885Sahrens return (ENOENT); 861885Sahrens } 862885Sahrens 863885Sahrens if (strlen(attr.za_name) + 1 > namelen) { 864885Sahrens zap_cursor_fini(&cursor); 865885Sahrens return (ENAMETOOLONG); 866885Sahrens } 867885Sahrens 868885Sahrens (void) strcpy(name, attr.za_name); 869885Sahrens if (idp) 870885Sahrens *idp = attr.za_first_integer; 871885Sahrens zap_cursor_advance(&cursor); 872885Sahrens *offp = zap_cursor_serialize(&cursor); 873885Sahrens zap_cursor_fini(&cursor); 874885Sahrens 875885Sahrens return (0); 876885Sahrens } 877885Sahrens 878885Sahrens int 879885Sahrens dmu_dir_list_next(objset_t *os, int namelen, char *name, 880885Sahrens uint64_t *idp, uint64_t *offp) 881885Sahrens { 882885Sahrens dsl_dir_t *dd = os->os->os_dsl_dataset->ds_dir; 883885Sahrens zap_cursor_t cursor; 884885Sahrens zap_attribute_t attr; 885885Sahrens 886885Sahrens /* there is no next dir on a snapshot! */ 887885Sahrens if (os->os->os_dsl_dataset->ds_object != 888885Sahrens dd->dd_phys->dd_head_dataset_obj) 889885Sahrens return (ENOENT); 890885Sahrens 891885Sahrens zap_cursor_init_serialized(&cursor, 892885Sahrens dd->dd_pool->dp_meta_objset, 893885Sahrens dd->dd_phys->dd_child_dir_zapobj, *offp); 894885Sahrens 895885Sahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 896885Sahrens zap_cursor_fini(&cursor); 897885Sahrens return (ENOENT); 898885Sahrens } 899885Sahrens 900885Sahrens if (strlen(attr.za_name) + 1 > namelen) { 901885Sahrens zap_cursor_fini(&cursor); 902789Sahrens return (ENAMETOOLONG); 903885Sahrens } 904789Sahrens 905789Sahrens (void) strcpy(name, attr.za_name); 906885Sahrens if (idp) 907885Sahrens *idp = attr.za_first_integer; 908789Sahrens zap_cursor_advance(&cursor); 909789Sahrens *offp = zap_cursor_serialize(&cursor); 910885Sahrens zap_cursor_fini(&cursor); 911789Sahrens 912789Sahrens return (0); 913789Sahrens } 914789Sahrens 915789Sahrens /* 916789Sahrens * Find all objsets under name, and for each, call 'func(child_name, arg)'. 917789Sahrens */ 9182199Sahrens int 9192199Sahrens dmu_objset_find(char *name, int func(char *, void *), void *arg, int flags) 920789Sahrens { 921789Sahrens dsl_dir_t *dd; 922789Sahrens objset_t *os; 923789Sahrens uint64_t snapobj; 924789Sahrens zap_cursor_t zc; 925789Sahrens zap_attribute_t attr; 926789Sahrens char *child; 9271544Seschrock int do_self, err; 928789Sahrens 9291544Seschrock err = dsl_dir_open(name, FTAG, &dd, NULL); 9301544Seschrock if (err) 9312199Sahrens return (err); 932789Sahrens 9332199Sahrens /* NB: the $MOS dir doesn't have a head dataset */ 934789Sahrens do_self = (dd->dd_phys->dd_head_dataset_obj != 0); 935789Sahrens 936789Sahrens /* 937789Sahrens * Iterate over all children. 938789Sahrens */ 9392417Sahrens if (flags & DS_FIND_CHILDREN) { 9402417Sahrens for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, 9412417Sahrens dd->dd_phys->dd_child_dir_zapobj); 9422417Sahrens zap_cursor_retrieve(&zc, &attr) == 0; 9432417Sahrens (void) zap_cursor_advance(&zc)) { 9442417Sahrens ASSERT(attr.za_integer_length == sizeof (uint64_t)); 9452417Sahrens ASSERT(attr.za_num_integers == 1); 946789Sahrens 9472417Sahrens /* 9482417Sahrens * No separating '/' because parent's name ends in /. 9492417Sahrens */ 9502417Sahrens child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 9512417Sahrens /* XXX could probably just use name here */ 9522417Sahrens dsl_dir_name(dd, child); 9532417Sahrens (void) strcat(child, "/"); 9542417Sahrens (void) strcat(child, attr.za_name); 9552417Sahrens err = dmu_objset_find(child, func, arg, flags); 9562417Sahrens kmem_free(child, MAXPATHLEN); 9572417Sahrens if (err) 9582417Sahrens break; 9592417Sahrens } 9602417Sahrens zap_cursor_fini(&zc); 9612199Sahrens 9622417Sahrens if (err) { 9632417Sahrens dsl_dir_close(dd, FTAG); 9642417Sahrens return (err); 9652417Sahrens } 966789Sahrens } 967789Sahrens 968789Sahrens /* 969789Sahrens * Iterate over all snapshots. 970789Sahrens */ 971789Sahrens if ((flags & DS_FIND_SNAPSHOTS) && 972789Sahrens dmu_objset_open(name, DMU_OST_ANY, 973789Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os) == 0) { 974789Sahrens 975789Sahrens snapobj = os->os->os_dsl_dataset->ds_phys->ds_snapnames_zapobj; 976789Sahrens dmu_objset_close(os); 977789Sahrens 978789Sahrens for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, snapobj); 979789Sahrens zap_cursor_retrieve(&zc, &attr) == 0; 980789Sahrens (void) zap_cursor_advance(&zc)) { 981789Sahrens ASSERT(attr.za_integer_length == sizeof (uint64_t)); 982789Sahrens ASSERT(attr.za_num_integers == 1); 983789Sahrens 984789Sahrens child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 985789Sahrens /* XXX could probably just use name here */ 986789Sahrens dsl_dir_name(dd, child); 987789Sahrens (void) strcat(child, "@"); 988789Sahrens (void) strcat(child, attr.za_name); 9892199Sahrens err = func(child, arg); 990789Sahrens kmem_free(child, MAXPATHLEN); 9912199Sahrens if (err) 9922199Sahrens break; 993789Sahrens } 994885Sahrens zap_cursor_fini(&zc); 995789Sahrens } 996789Sahrens 997789Sahrens dsl_dir_close(dd, FTAG); 998789Sahrens 9992199Sahrens if (err) 10002199Sahrens return (err); 10012199Sahrens 1002789Sahrens /* 1003789Sahrens * Apply to self if appropriate. 1004789Sahrens */ 1005789Sahrens if (do_self) 10062199Sahrens err = func(name, arg); 10072199Sahrens return (err); 1008789Sahrens } 1009