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 /* 22c717a561Smaybee * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/zfs_context.h> 29fa9e4066Sahrens #include <sys/dmu_objset.h> 30fa9e4066Sahrens #include <sys/dsl_dir.h> 31fa9e4066Sahrens #include <sys/dsl_dataset.h> 32fa9e4066Sahrens #include <sys/dsl_prop.h> 33fa9e4066Sahrens #include <sys/dsl_pool.h> 341d452cf5Sahrens #include <sys/dsl_synctask.h> 35fa9e4066Sahrens #include <sys/dnode.h> 36fa9e4066Sahrens #include <sys/dbuf.h> 37a2eea2e1Sahrens #include <sys/zvol.h> 38fa9e4066Sahrens #include <sys/dmu_tx.h> 39fa9e4066Sahrens #include <sys/zio_checksum.h> 40fa9e4066Sahrens #include <sys/zap.h> 41fa9e4066Sahrens #include <sys/zil.h> 42fa9e4066Sahrens #include <sys/dmu_impl.h> 43fa9e4066Sahrens 44fa9e4066Sahrens 45fa9e4066Sahrens spa_t * 46fa9e4066Sahrens dmu_objset_spa(objset_t *os) 47fa9e4066Sahrens { 48fa9e4066Sahrens return (os->os->os_spa); 49fa9e4066Sahrens } 50fa9e4066Sahrens 51fa9e4066Sahrens zilog_t * 52fa9e4066Sahrens dmu_objset_zil(objset_t *os) 53fa9e4066Sahrens { 54fa9e4066Sahrens return (os->os->os_zil); 55fa9e4066Sahrens } 56fa9e4066Sahrens 57fa9e4066Sahrens dsl_pool_t * 58fa9e4066Sahrens dmu_objset_pool(objset_t *os) 59fa9e4066Sahrens { 60fa9e4066Sahrens dsl_dataset_t *ds; 61fa9e4066Sahrens 62fa9e4066Sahrens if ((ds = os->os->os_dsl_dataset) != NULL && ds->ds_dir) 63fa9e4066Sahrens return (ds->ds_dir->dd_pool); 64fa9e4066Sahrens else 65fa9e4066Sahrens return (spa_get_dsl(os->os->os_spa)); 66fa9e4066Sahrens } 67fa9e4066Sahrens 68fa9e4066Sahrens dsl_dataset_t * 69fa9e4066Sahrens dmu_objset_ds(objset_t *os) 70fa9e4066Sahrens { 71fa9e4066Sahrens return (os->os->os_dsl_dataset); 72fa9e4066Sahrens } 73fa9e4066Sahrens 74fa9e4066Sahrens dmu_objset_type_t 75fa9e4066Sahrens dmu_objset_type(objset_t *os) 76fa9e4066Sahrens { 77fa9e4066Sahrens return (os->os->os_phys->os_type); 78fa9e4066Sahrens } 79fa9e4066Sahrens 80fa9e4066Sahrens void 81fa9e4066Sahrens dmu_objset_name(objset_t *os, char *buf) 82fa9e4066Sahrens { 83fa9e4066Sahrens dsl_dataset_name(os->os->os_dsl_dataset, buf); 84fa9e4066Sahrens } 85fa9e4066Sahrens 86fa9e4066Sahrens uint64_t 87fa9e4066Sahrens dmu_objset_id(objset_t *os) 88fa9e4066Sahrens { 89fa9e4066Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 90fa9e4066Sahrens 91fa9e4066Sahrens return (ds ? ds->ds_object : 0); 92fa9e4066Sahrens } 93fa9e4066Sahrens 94fa9e4066Sahrens static void 95fa9e4066Sahrens checksum_changed_cb(void *arg, uint64_t newval) 96fa9e4066Sahrens { 97fa9e4066Sahrens objset_impl_t *osi = arg; 98fa9e4066Sahrens 99fa9e4066Sahrens /* 100fa9e4066Sahrens * Inheritance should have been done by now. 101fa9e4066Sahrens */ 102fa9e4066Sahrens ASSERT(newval != ZIO_CHECKSUM_INHERIT); 103fa9e4066Sahrens 104fa9e4066Sahrens osi->os_checksum = zio_checksum_select(newval, ZIO_CHECKSUM_ON_VALUE); 105fa9e4066Sahrens } 106fa9e4066Sahrens 107fa9e4066Sahrens static void 108fa9e4066Sahrens compression_changed_cb(void *arg, uint64_t newval) 109fa9e4066Sahrens { 110fa9e4066Sahrens objset_impl_t *osi = arg; 111fa9e4066Sahrens 112fa9e4066Sahrens /* 113fa9e4066Sahrens * Inheritance and range checking should have been done by now. 114fa9e4066Sahrens */ 115fa9e4066Sahrens ASSERT(newval != ZIO_COMPRESS_INHERIT); 116fa9e4066Sahrens 117fa9e4066Sahrens osi->os_compress = zio_compress_select(newval, ZIO_COMPRESS_ON_VALUE); 118fa9e4066Sahrens } 119fa9e4066Sahrens 120*d0ad202dSahrens static void 121*d0ad202dSahrens copies_changed_cb(void *arg, uint64_t newval) 122*d0ad202dSahrens { 123*d0ad202dSahrens objset_impl_t *osi = arg; 124*d0ad202dSahrens 125*d0ad202dSahrens /* 126*d0ad202dSahrens * Inheritance and range checking should have been done by now. 127*d0ad202dSahrens */ 128*d0ad202dSahrens ASSERT(newval > 0); 129*d0ad202dSahrens ASSERT(newval <= spa_max_replication(osi->os_spa)); 130*d0ad202dSahrens 131*d0ad202dSahrens osi->os_copies = newval; 132*d0ad202dSahrens } 133*d0ad202dSahrens 134fa9e4066Sahrens void 135fa9e4066Sahrens dmu_objset_byteswap(void *buf, size_t size) 136fa9e4066Sahrens { 137fa9e4066Sahrens objset_phys_t *osp = buf; 138fa9e4066Sahrens 139fa9e4066Sahrens ASSERT(size == sizeof (objset_phys_t)); 140fa9e4066Sahrens dnode_byteswap(&osp->os_meta_dnode); 141fa9e4066Sahrens byteswap_uint64_array(&osp->os_zil_header, sizeof (zil_header_t)); 142fa9e4066Sahrens osp->os_type = BSWAP_64(osp->os_type); 143fa9e4066Sahrens } 144fa9e4066Sahrens 145ea8dc4b6Seschrock int 146ea8dc4b6Seschrock dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 147ea8dc4b6Seschrock objset_impl_t **osip) 148fa9e4066Sahrens { 149fa9e4066Sahrens objset_impl_t *winner, *osi; 150fa9e4066Sahrens int i, err, checksum; 151fa9e4066Sahrens 152fa9e4066Sahrens osi = kmem_zalloc(sizeof (objset_impl_t), KM_SLEEP); 153fa9e4066Sahrens osi->os.os = osi; 154fa9e4066Sahrens osi->os_dsl_dataset = ds; 155fa9e4066Sahrens osi->os_spa = spa; 156c717a561Smaybee osi->os_rootbp = bp; 157c717a561Smaybee if (!BP_IS_HOLE(osi->os_rootbp)) { 15813506d1eSmaybee uint32_t aflags = ARC_WAIT; 159ea8dc4b6Seschrock zbookmark_t zb; 160ea8dc4b6Seschrock zb.zb_objset = ds ? ds->ds_object : 0; 161ea8dc4b6Seschrock zb.zb_object = 0; 162ea8dc4b6Seschrock zb.zb_level = -1; 163ea8dc4b6Seschrock zb.zb_blkid = 0; 164ea8dc4b6Seschrock 165c717a561Smaybee dprintf_bp(osi->os_rootbp, "reading %s", ""); 166c717a561Smaybee err = arc_read(NULL, spa, osi->os_rootbp, 167fa9e4066Sahrens dmu_ot[DMU_OT_OBJSET].ot_byteswap, 168c717a561Smaybee arc_getbuf_func, &osi->os_phys_buf, 16913506d1eSmaybee ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &aflags, &zb); 170ea8dc4b6Seschrock if (err) { 171ea8dc4b6Seschrock kmem_free(osi, sizeof (objset_impl_t)); 172ea8dc4b6Seschrock return (err); 173ea8dc4b6Seschrock } 174c717a561Smaybee osi->os_phys = osi->os_phys_buf->b_data; 175c717a561Smaybee arc_release(osi->os_phys_buf, &osi->os_phys_buf); 176fa9e4066Sahrens } else { 177c717a561Smaybee osi->os_phys_buf = arc_buf_alloc(spa, sizeof (objset_phys_t), 178c717a561Smaybee &osi->os_phys_buf, ARC_BUFC_METADATA); 179c717a561Smaybee osi->os_phys = osi->os_phys_buf->b_data; 180fa9e4066Sahrens bzero(osi->os_phys, sizeof (objset_phys_t)); 181fa9e4066Sahrens } 182fa9e4066Sahrens 183fa9e4066Sahrens /* 184fa9e4066Sahrens * Note: the changed_cb will be called once before the register 185fa9e4066Sahrens * func returns, thus changing the checksum/compression from the 18699653d4eSeschrock * default (fletcher2/off). Snapshots don't need to know, and 18799653d4eSeschrock * registering would complicate clone promotion. 188fa9e4066Sahrens */ 18999653d4eSeschrock if (ds && ds->ds_phys->ds_num_children == 0) { 190fa9e4066Sahrens err = dsl_prop_register(ds, "checksum", 191fa9e4066Sahrens checksum_changed_cb, osi); 192ea8dc4b6Seschrock if (err == 0) 193ea8dc4b6Seschrock err = dsl_prop_register(ds, "compression", 194ea8dc4b6Seschrock compression_changed_cb, osi); 195*d0ad202dSahrens if (err == 0) 196*d0ad202dSahrens err = dsl_prop_register(ds, "copies", 197*d0ad202dSahrens copies_changed_cb, osi); 198ea8dc4b6Seschrock if (err) { 199c717a561Smaybee VERIFY(arc_buf_remove_ref(osi->os_phys_buf, 200c717a561Smaybee &osi->os_phys_buf) == 1); 201ea8dc4b6Seschrock kmem_free(osi, sizeof (objset_impl_t)); 202ea8dc4b6Seschrock return (err); 203ea8dc4b6Seschrock } 20499653d4eSeschrock } else if (ds == NULL) { 205fa9e4066Sahrens /* It's the meta-objset. */ 206fa9e4066Sahrens osi->os_checksum = ZIO_CHECKSUM_FLETCHER_4; 207ea8dc4b6Seschrock osi->os_compress = ZIO_COMPRESS_LZJB; 208*d0ad202dSahrens osi->os_copies = spa_max_replication(spa); 209fa9e4066Sahrens } 210fa9e4066Sahrens 211ea8dc4b6Seschrock osi->os_zil = zil_alloc(&osi->os, &osi->os_phys->os_zil_header); 212ea8dc4b6Seschrock 213fa9e4066Sahrens /* 214fa9e4066Sahrens * Metadata always gets compressed and checksummed. 215fa9e4066Sahrens * If the data checksum is multi-bit correctable, and it's not 216fa9e4066Sahrens * a ZBT-style checksum, then it's suitable for metadata as well. 217fa9e4066Sahrens * Otherwise, the metadata checksum defaults to fletcher4. 218fa9e4066Sahrens */ 219fa9e4066Sahrens checksum = osi->os_checksum; 220fa9e4066Sahrens 221fa9e4066Sahrens if (zio_checksum_table[checksum].ci_correctable && 222fa9e4066Sahrens !zio_checksum_table[checksum].ci_zbt) 223fa9e4066Sahrens osi->os_md_checksum = checksum; 224fa9e4066Sahrens else 225fa9e4066Sahrens osi->os_md_checksum = ZIO_CHECKSUM_FLETCHER_4; 226ea8dc4b6Seschrock osi->os_md_compress = ZIO_COMPRESS_LZJB; 227fa9e4066Sahrens 228fa9e4066Sahrens for (i = 0; i < TXG_SIZE; i++) { 229fa9e4066Sahrens list_create(&osi->os_dirty_dnodes[i], sizeof (dnode_t), 230fa9e4066Sahrens offsetof(dnode_t, dn_dirty_link[i])); 231fa9e4066Sahrens list_create(&osi->os_free_dnodes[i], sizeof (dnode_t), 232fa9e4066Sahrens offsetof(dnode_t, dn_dirty_link[i])); 233fa9e4066Sahrens } 234fa9e4066Sahrens list_create(&osi->os_dnodes, sizeof (dnode_t), 235fa9e4066Sahrens offsetof(dnode_t, dn_link)); 236fa9e4066Sahrens list_create(&osi->os_downgraded_dbufs, sizeof (dmu_buf_impl_t), 237fa9e4066Sahrens offsetof(dmu_buf_impl_t, db_link)); 238fa9e4066Sahrens 2395ad82045Snd mutex_init(&osi->os_lock, NULL, MUTEX_DEFAULT, NULL); 2405ad82045Snd mutex_init(&osi->os_obj_lock, NULL, MUTEX_DEFAULT, NULL); 2415ad82045Snd 242fa9e4066Sahrens osi->os_meta_dnode = dnode_special_open(osi, 243fa9e4066Sahrens &osi->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT); 244fa9e4066Sahrens 245fa9e4066Sahrens if (ds != NULL) { 246fa9e4066Sahrens winner = dsl_dataset_set_user_ptr(ds, osi, dmu_objset_evict); 247fa9e4066Sahrens if (winner) { 248fa9e4066Sahrens dmu_objset_evict(ds, osi); 249fa9e4066Sahrens osi = winner; 250fa9e4066Sahrens } 251fa9e4066Sahrens } 252fa9e4066Sahrens 253ea8dc4b6Seschrock *osip = osi; 254ea8dc4b6Seschrock return (0); 255fa9e4066Sahrens } 256fa9e4066Sahrens 257fa9e4066Sahrens /* called from zpl */ 258fa9e4066Sahrens int 259fa9e4066Sahrens dmu_objset_open(const char *name, dmu_objset_type_t type, int mode, 260fa9e4066Sahrens objset_t **osp) 261fa9e4066Sahrens { 262fa9e4066Sahrens dsl_dataset_t *ds; 263fa9e4066Sahrens int err; 264fa9e4066Sahrens objset_t *os; 265fa9e4066Sahrens objset_impl_t *osi; 266fa9e4066Sahrens 267fa9e4066Sahrens os = kmem_alloc(sizeof (objset_t), KM_SLEEP); 268fa9e4066Sahrens err = dsl_dataset_open(name, mode, os, &ds); 269fa9e4066Sahrens if (err) { 270fa9e4066Sahrens kmem_free(os, sizeof (objset_t)); 271fa9e4066Sahrens return (err); 272fa9e4066Sahrens } 273fa9e4066Sahrens 274fa9e4066Sahrens osi = dsl_dataset_get_user_ptr(ds); 275fa9e4066Sahrens if (osi == NULL) { 276ea8dc4b6Seschrock err = dmu_objset_open_impl(dsl_dataset_get_spa(ds), 277c717a561Smaybee ds, &ds->ds_phys->ds_bp, &osi); 278ea8dc4b6Seschrock if (err) { 279ea8dc4b6Seschrock dsl_dataset_close(ds, mode, os); 280ea8dc4b6Seschrock kmem_free(os, sizeof (objset_t)); 281ea8dc4b6Seschrock return (err); 282ea8dc4b6Seschrock } 283fa9e4066Sahrens } 284fa9e4066Sahrens 285fa9e4066Sahrens os->os = osi; 286fa9e4066Sahrens os->os_mode = mode; 287fa9e4066Sahrens 288fa9e4066Sahrens if (type != DMU_OST_ANY && type != os->os->os_phys->os_type) { 289fa9e4066Sahrens dmu_objset_close(os); 290fa9e4066Sahrens return (EINVAL); 291fa9e4066Sahrens } 292fa9e4066Sahrens *osp = os; 293fa9e4066Sahrens return (0); 294fa9e4066Sahrens } 295fa9e4066Sahrens 296fa9e4066Sahrens void 297fa9e4066Sahrens dmu_objset_close(objset_t *os) 298fa9e4066Sahrens { 299fa9e4066Sahrens dsl_dataset_close(os->os->os_dsl_dataset, os->os_mode, os); 300fa9e4066Sahrens kmem_free(os, sizeof (objset_t)); 301fa9e4066Sahrens } 302fa9e4066Sahrens 303436b2950Sperrin int 304436b2950Sperrin dmu_objset_evict_dbufs(objset_t *os, int try) 305ea8dc4b6Seschrock { 306ea8dc4b6Seschrock objset_impl_t *osi = os->os; 307ea8dc4b6Seschrock dnode_t *dn; 308c543ec06Sahrens 309c543ec06Sahrens mutex_enter(&osi->os_lock); 310c543ec06Sahrens 311c543ec06Sahrens /* process the mdn last, since the other dnodes have holds on it */ 312c543ec06Sahrens list_remove(&osi->os_dnodes, osi->os_meta_dnode); 313c543ec06Sahrens list_insert_tail(&osi->os_dnodes, osi->os_meta_dnode); 314ea8dc4b6Seschrock 315ea8dc4b6Seschrock /* 316c543ec06Sahrens * Find the first dnode with holds. We have to do this dance 317c543ec06Sahrens * because dnode_add_ref() only works if you already have a 318c543ec06Sahrens * hold. If there are no holds then it has no dbufs so OK to 319c543ec06Sahrens * skip. 320ea8dc4b6Seschrock */ 321c543ec06Sahrens for (dn = list_head(&osi->os_dnodes); 322c543ec06Sahrens dn && refcount_is_zero(&dn->dn_holds); 323c543ec06Sahrens dn = list_next(&osi->os_dnodes, dn)) 324c543ec06Sahrens continue; 325c543ec06Sahrens if (dn) 326c543ec06Sahrens dnode_add_ref(dn, FTAG); 327c543ec06Sahrens 328c543ec06Sahrens while (dn) { 329c543ec06Sahrens dnode_t *next_dn = dn; 330c543ec06Sahrens 331c543ec06Sahrens do { 332c543ec06Sahrens next_dn = list_next(&osi->os_dnodes, next_dn); 333c543ec06Sahrens } while (next_dn && refcount_is_zero(&next_dn->dn_holds)); 334c543ec06Sahrens if (next_dn) 335c543ec06Sahrens dnode_add_ref(next_dn, FTAG); 336c543ec06Sahrens 337c543ec06Sahrens mutex_exit(&osi->os_lock); 338436b2950Sperrin if (dnode_evict_dbufs(dn, try)) { 339436b2950Sperrin dnode_rele(dn, FTAG); 340436b2950Sperrin if (next_dn) 341436b2950Sperrin dnode_rele(next_dn, FTAG); 342436b2950Sperrin return (1); 343436b2950Sperrin } 344c543ec06Sahrens dnode_rele(dn, FTAG); 345c543ec06Sahrens mutex_enter(&osi->os_lock); 346c543ec06Sahrens dn = next_dn; 347ea8dc4b6Seschrock } 348ea8dc4b6Seschrock mutex_exit(&osi->os_lock); 349436b2950Sperrin return (0); 350ea8dc4b6Seschrock } 351ea8dc4b6Seschrock 352fa9e4066Sahrens void 353fa9e4066Sahrens dmu_objset_evict(dsl_dataset_t *ds, void *arg) 354fa9e4066Sahrens { 355fa9e4066Sahrens objset_impl_t *osi = arg; 356ea8dc4b6Seschrock objset_t os; 35799653d4eSeschrock int i; 358fa9e4066Sahrens 359fa9e4066Sahrens for (i = 0; i < TXG_SIZE; i++) { 360fa9e4066Sahrens ASSERT(list_head(&osi->os_dirty_dnodes[i]) == NULL); 361fa9e4066Sahrens ASSERT(list_head(&osi->os_free_dnodes[i]) == NULL); 362fa9e4066Sahrens } 363fa9e4066Sahrens 36499653d4eSeschrock if (ds && ds->ds_phys->ds_num_children == 0) { 36599653d4eSeschrock VERIFY(0 == dsl_prop_unregister(ds, "checksum", 36699653d4eSeschrock checksum_changed_cb, osi)); 36799653d4eSeschrock VERIFY(0 == dsl_prop_unregister(ds, "compression", 36899653d4eSeschrock compression_changed_cb, osi)); 369*d0ad202dSahrens VERIFY(0 == dsl_prop_unregister(ds, "copies", 370*d0ad202dSahrens copies_changed_cb, osi)); 371fa9e4066Sahrens } 372fa9e4066Sahrens 373ea8dc4b6Seschrock /* 374ea8dc4b6Seschrock * We should need only a single pass over the dnode list, since 375ea8dc4b6Seschrock * nothing can be added to the list at this point. 376ea8dc4b6Seschrock */ 377ea8dc4b6Seschrock os.os = osi; 378436b2950Sperrin (void) dmu_objset_evict_dbufs(&os, 0); 379ea8dc4b6Seschrock 380fa9e4066Sahrens ASSERT3P(list_head(&osi->os_dnodes), ==, osi->os_meta_dnode); 381fa9e4066Sahrens ASSERT3P(list_tail(&osi->os_dnodes), ==, osi->os_meta_dnode); 382fa9e4066Sahrens ASSERT3P(list_head(&osi->os_meta_dnode->dn_dbufs), ==, NULL); 383fa9e4066Sahrens 384fa9e4066Sahrens dnode_special_close(osi->os_meta_dnode); 385fa9e4066Sahrens zil_free(osi->os_zil); 386fa9e4066Sahrens 387c717a561Smaybee VERIFY(arc_buf_remove_ref(osi->os_phys_buf, &osi->os_phys_buf) == 1); 3885ad82045Snd mutex_destroy(&osi->os_lock); 3895ad82045Snd mutex_destroy(&osi->os_obj_lock); 390fa9e4066Sahrens kmem_free(osi, sizeof (objset_impl_t)); 391fa9e4066Sahrens } 392fa9e4066Sahrens 393fa9e4066Sahrens /* called from dsl for meta-objset */ 394fa9e4066Sahrens objset_impl_t * 395c717a561Smaybee dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 396c717a561Smaybee dmu_objset_type_t type, dmu_tx_t *tx) 397fa9e4066Sahrens { 398fa9e4066Sahrens objset_impl_t *osi; 399fa9e4066Sahrens dnode_t *mdn; 400fa9e4066Sahrens 401fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 402c717a561Smaybee VERIFY(0 == dmu_objset_open_impl(spa, ds, bp, &osi)); 403fa9e4066Sahrens mdn = osi->os_meta_dnode; 404fa9e4066Sahrens 405fa9e4066Sahrens dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT, 406fa9e4066Sahrens DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx); 407fa9e4066Sahrens 408fa9e4066Sahrens /* 409fa9e4066Sahrens * We don't want to have to increase the meta-dnode's nlevels 410fa9e4066Sahrens * later, because then we could do it in quescing context while 411fa9e4066Sahrens * we are also accessing it in open context. 412fa9e4066Sahrens * 413fa9e4066Sahrens * This precaution is not necessary for the MOS (ds == NULL), 414fa9e4066Sahrens * because the MOS is only updated in syncing context. 415fa9e4066Sahrens * This is most fortunate: the MOS is the only objset that 416fa9e4066Sahrens * needs to be synced multiple times as spa_sync() iterates 417fa9e4066Sahrens * to convergence, so minimizing its dn_nlevels matters. 418fa9e4066Sahrens */ 419ea8dc4b6Seschrock if (ds != NULL) { 420ea8dc4b6Seschrock int levels = 1; 421ea8dc4b6Seschrock 422ea8dc4b6Seschrock /* 423ea8dc4b6Seschrock * Determine the number of levels necessary for the meta-dnode 424ea8dc4b6Seschrock * to contain DN_MAX_OBJECT dnodes. 425ea8dc4b6Seschrock */ 426ea8dc4b6Seschrock while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift + 427ea8dc4b6Seschrock (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) < 428ea8dc4b6Seschrock DN_MAX_OBJECT * sizeof (dnode_phys_t)) 429ea8dc4b6Seschrock levels++; 430ea8dc4b6Seschrock 431fa9e4066Sahrens mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = 432ea8dc4b6Seschrock mdn->dn_nlevels = levels; 433ea8dc4b6Seschrock } 434fa9e4066Sahrens 435fa9e4066Sahrens ASSERT(type != DMU_OST_NONE); 436fa9e4066Sahrens ASSERT(type != DMU_OST_ANY); 437fa9e4066Sahrens ASSERT(type < DMU_OST_NUMTYPES); 438fa9e4066Sahrens osi->os_phys->os_type = type; 439fa9e4066Sahrens 440fa9e4066Sahrens dsl_dataset_dirty(ds, tx); 441fa9e4066Sahrens 442fa9e4066Sahrens return (osi); 443fa9e4066Sahrens } 444fa9e4066Sahrens 445fa9e4066Sahrens struct oscarg { 446fa9e4066Sahrens void (*userfunc)(objset_t *os, void *arg, dmu_tx_t *tx); 447fa9e4066Sahrens void *userarg; 448fa9e4066Sahrens dsl_dataset_t *clone_parent; 449fa9e4066Sahrens const char *lastname; 450fa9e4066Sahrens dmu_objset_type_t type; 451fa9e4066Sahrens }; 452fa9e4066Sahrens 4531d452cf5Sahrens /* ARGSUSED */ 454fa9e4066Sahrens static int 4551d452cf5Sahrens dmu_objset_create_check(void *arg1, void *arg2, dmu_tx_t *tx) 456fa9e4066Sahrens { 4571d452cf5Sahrens dsl_dir_t *dd = arg1; 4581d452cf5Sahrens struct oscarg *oa = arg2; 4591d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 460fa9e4066Sahrens int err; 4611d452cf5Sahrens uint64_t ddobj; 4621d452cf5Sahrens 4631d452cf5Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 4641d452cf5Sahrens oa->lastname, sizeof (uint64_t), 1, &ddobj); 4651d452cf5Sahrens if (err != ENOENT) 4661d452cf5Sahrens return (err ? err : EEXIST); 4671d452cf5Sahrens 4681d452cf5Sahrens if (oa->clone_parent != NULL) { 4691d452cf5Sahrens /* 4701d452cf5Sahrens * You can't clone across pools. 4711d452cf5Sahrens */ 4721d452cf5Sahrens if (oa->clone_parent->ds_dir->dd_pool != dd->dd_pool) 4731d452cf5Sahrens return (EXDEV); 4741d452cf5Sahrens 4751d452cf5Sahrens /* 4761d452cf5Sahrens * You can only clone snapshots, not the head datasets. 4771d452cf5Sahrens */ 4781d452cf5Sahrens if (oa->clone_parent->ds_phys->ds_num_children == 0) 4791d452cf5Sahrens return (EINVAL); 4801d452cf5Sahrens } 4811d452cf5Sahrens return (0); 4821d452cf5Sahrens } 4831d452cf5Sahrens 4841d452cf5Sahrens static void 4851d452cf5Sahrens dmu_objset_create_sync(void *arg1, void *arg2, dmu_tx_t *tx) 4861d452cf5Sahrens { 4871d452cf5Sahrens dsl_dir_t *dd = arg1; 4881d452cf5Sahrens struct oscarg *oa = arg2; 4891d452cf5Sahrens dsl_dataset_t *ds; 490c717a561Smaybee blkptr_t *bp; 4911d452cf5Sahrens uint64_t dsobj; 492fa9e4066Sahrens 493fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 494fa9e4066Sahrens 4951d452cf5Sahrens dsobj = dsl_dataset_create_sync(dd, oa->lastname, 496fa9e4066Sahrens oa->clone_parent, tx); 497fa9e4066Sahrens 4981d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 499ea8dc4b6Seschrock DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ds)); 500c717a561Smaybee bp = dsl_dataset_get_blkptr(ds); 501c717a561Smaybee if (BP_IS_HOLE(bp)) { 502fa9e4066Sahrens objset_impl_t *osi; 503fa9e4066Sahrens 504fa9e4066Sahrens /* This is an empty dmu_objset; not a clone. */ 505fa9e4066Sahrens osi = dmu_objset_create_impl(dsl_dataset_get_spa(ds), 506c717a561Smaybee ds, bp, oa->type, tx); 507fa9e4066Sahrens 508fa9e4066Sahrens if (oa->userfunc) 509fa9e4066Sahrens oa->userfunc(&osi->os, oa->userarg, tx); 510fa9e4066Sahrens } 511fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG); 512fa9e4066Sahrens } 513fa9e4066Sahrens 514fa9e4066Sahrens int 515fa9e4066Sahrens dmu_objset_create(const char *name, dmu_objset_type_t type, 516fa9e4066Sahrens objset_t *clone_parent, 517fa9e4066Sahrens void (*func)(objset_t *os, void *arg, dmu_tx_t *tx), void *arg) 518fa9e4066Sahrens { 5191d452cf5Sahrens dsl_dir_t *pdd; 520fa9e4066Sahrens const char *tail; 521fa9e4066Sahrens int err = 0; 5221d452cf5Sahrens struct oscarg oa = { 0 }; 523fa9e4066Sahrens 5241d452cf5Sahrens ASSERT(strchr(name, '@') == NULL); 5251d452cf5Sahrens err = dsl_dir_open(name, FTAG, &pdd, &tail); 526ea8dc4b6Seschrock if (err) 527ea8dc4b6Seschrock return (err); 528fa9e4066Sahrens if (tail == NULL) { 5291d452cf5Sahrens dsl_dir_close(pdd, FTAG); 530fa9e4066Sahrens return (EEXIST); 531fa9e4066Sahrens } 532fa9e4066Sahrens 533fa9e4066Sahrens dprintf("name=%s\n", name); 534fa9e4066Sahrens 5351d452cf5Sahrens oa.userfunc = func; 5361d452cf5Sahrens oa.userarg = arg; 5371d452cf5Sahrens oa.lastname = tail; 5381d452cf5Sahrens oa.type = type; 5391d452cf5Sahrens if (clone_parent != NULL) { 540fa9e4066Sahrens /* 5411d452cf5Sahrens * You can't clone to a different type. 542fa9e4066Sahrens */ 5431d452cf5Sahrens if (clone_parent->os->os_phys->os_type != type) { 5441d452cf5Sahrens dsl_dir_close(pdd, FTAG); 5451d452cf5Sahrens return (EINVAL); 546fa9e4066Sahrens } 5471d452cf5Sahrens oa.clone_parent = clone_parent->os->os_dsl_dataset; 548fa9e4066Sahrens } 5491d452cf5Sahrens err = dsl_sync_task_do(pdd->dd_pool, dmu_objset_create_check, 5501d452cf5Sahrens dmu_objset_create_sync, pdd, &oa, 5); 5511d452cf5Sahrens dsl_dir_close(pdd, FTAG); 552fa9e4066Sahrens return (err); 553fa9e4066Sahrens } 554fa9e4066Sahrens 555fa9e4066Sahrens int 556fa9e4066Sahrens dmu_objset_destroy(const char *name) 557fa9e4066Sahrens { 558fa9e4066Sahrens objset_t *os; 559fa9e4066Sahrens int error; 560fa9e4066Sahrens 561fa9e4066Sahrens /* 562fa9e4066Sahrens * If it looks like we'll be able to destroy it, and there's 563fa9e4066Sahrens * an unplayed replay log sitting around, destroy the log. 564fa9e4066Sahrens * It would be nicer to do this in dsl_dataset_destroy_sync(), 565fa9e4066Sahrens * but the replay log objset is modified in open context. 566fa9e4066Sahrens */ 567fa9e4066Sahrens error = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 568fa9e4066Sahrens if (error == 0) { 569d80c45e0Sbonwick zil_destroy(dmu_objset_zil(os), B_FALSE); 570fa9e4066Sahrens dmu_objset_close(os); 571fa9e4066Sahrens } 572fa9e4066Sahrens 573fa9e4066Sahrens return (dsl_dataset_destroy(name)); 574fa9e4066Sahrens } 575fa9e4066Sahrens 576fa9e4066Sahrens int 577fa9e4066Sahrens dmu_objset_rollback(const char *name) 578fa9e4066Sahrens { 579fa9e4066Sahrens int err; 580fa9e4066Sahrens objset_t *os; 581fa9e4066Sahrens 5821d452cf5Sahrens err = dmu_objset_open(name, DMU_OST_ANY, 5831d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); 584fa9e4066Sahrens if (err == 0) { 585fa9e4066Sahrens err = zil_suspend(dmu_objset_zil(os)); 586fa9e4066Sahrens if (err == 0) 587fa9e4066Sahrens zil_resume(dmu_objset_zil(os)); 588fa9e4066Sahrens if (err == 0) { 589fa9e4066Sahrens /* XXX uncache everything? */ 5901d452cf5Sahrens err = dsl_dataset_rollback(os->os->os_dsl_dataset); 591fa9e4066Sahrens } 5921d452cf5Sahrens dmu_objset_close(os); 593fa9e4066Sahrens } 594fa9e4066Sahrens return (err); 595fa9e4066Sahrens } 596fa9e4066Sahrens 5971d452cf5Sahrens struct snaparg { 5981d452cf5Sahrens dsl_sync_task_group_t *dstg; 5991d452cf5Sahrens char *snapname; 6001d452cf5Sahrens char failed[MAXPATHLEN]; 6011d452cf5Sahrens }; 6021d452cf5Sahrens 6031d452cf5Sahrens static int 6041d452cf5Sahrens dmu_objset_snapshot_one(char *name, void *arg) 6051d452cf5Sahrens { 6061d452cf5Sahrens struct snaparg *sn = arg; 6071d452cf5Sahrens objset_t *os; 608f2e10be3Srm dmu_objset_stats_t stat; 6091d452cf5Sahrens int err; 6101d452cf5Sahrens 6111d452cf5Sahrens (void) strcpy(sn->failed, name); 6121d452cf5Sahrens 6131d452cf5Sahrens err = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_STANDARD, &os); 6141d452cf5Sahrens if (err != 0) 6151d452cf5Sahrens return (err); 6161d452cf5Sahrens 617f2e10be3Srm /* 618f2e10be3Srm * If the objset is in an inconsistent state, return busy. 619f2e10be3Srm */ 620f2e10be3Srm dmu_objset_fast_stat(os, &stat); 621f2e10be3Srm if (stat.dds_inconsistent) { 622f2e10be3Srm dmu_objset_close(os); 623f2e10be3Srm return (EBUSY); 624f2e10be3Srm } 625f2e10be3Srm 6261d452cf5Sahrens /* 6271d452cf5Sahrens * NB: we need to wait for all in-flight changes to get to disk, 6281d452cf5Sahrens * so that we snapshot those changes. zil_suspend does this as 6291d452cf5Sahrens * a side effect. 6301d452cf5Sahrens */ 6311d452cf5Sahrens err = zil_suspend(dmu_objset_zil(os)); 6321d452cf5Sahrens if (err == 0) { 6331d452cf5Sahrens dsl_sync_task_create(sn->dstg, dsl_dataset_snapshot_check, 6341d452cf5Sahrens dsl_dataset_snapshot_sync, os, sn->snapname, 3); 635f2e10be3Srm } else { 636f2e10be3Srm dmu_objset_close(os); 6371d452cf5Sahrens } 638f2e10be3Srm 6391d452cf5Sahrens return (err); 6401d452cf5Sahrens } 6411d452cf5Sahrens 6421d452cf5Sahrens int 6431d452cf5Sahrens dmu_objset_snapshot(char *fsname, char *snapname, boolean_t recursive) 6441d452cf5Sahrens { 6451d452cf5Sahrens dsl_sync_task_t *dst; 6461d452cf5Sahrens struct snaparg sn = { 0 }; 6471d452cf5Sahrens char *cp; 6481d452cf5Sahrens spa_t *spa; 6491d452cf5Sahrens int err; 6501d452cf5Sahrens 6511d452cf5Sahrens (void) strcpy(sn.failed, fsname); 6521d452cf5Sahrens 6531d452cf5Sahrens cp = strchr(fsname, '/'); 6541d452cf5Sahrens if (cp) { 6551d452cf5Sahrens *cp = '\0'; 6561d452cf5Sahrens err = spa_open(fsname, &spa, FTAG); 6571d452cf5Sahrens *cp = '/'; 6581d452cf5Sahrens } else { 6591d452cf5Sahrens err = spa_open(fsname, &spa, FTAG); 6601d452cf5Sahrens } 6611d452cf5Sahrens if (err) 6621d452cf5Sahrens return (err); 6631d452cf5Sahrens 6641d452cf5Sahrens sn.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 6651d452cf5Sahrens sn.snapname = snapname; 6661d452cf5Sahrens 6670b69c2f0Sahrens if (recursive) { 6680b69c2f0Sahrens err = dmu_objset_find(fsname, 6690b69c2f0Sahrens dmu_objset_snapshot_one, &sn, DS_FIND_CHILDREN); 6700b69c2f0Sahrens } else { 6711d452cf5Sahrens err = dmu_objset_snapshot_one(fsname, &sn); 6720b69c2f0Sahrens } 6731d452cf5Sahrens 6741d452cf5Sahrens if (err) 6751d452cf5Sahrens goto out; 6761d452cf5Sahrens 6771d452cf5Sahrens err = dsl_sync_task_group_wait(sn.dstg); 6781d452cf5Sahrens 6791d452cf5Sahrens for (dst = list_head(&sn.dstg->dstg_tasks); dst; 6801d452cf5Sahrens dst = list_next(&sn.dstg->dstg_tasks, dst)) { 6811d452cf5Sahrens objset_t *os = dst->dst_arg1; 6821d452cf5Sahrens if (dst->dst_err) 6831d452cf5Sahrens dmu_objset_name(os, sn.failed); 6841d452cf5Sahrens zil_resume(dmu_objset_zil(os)); 6851d452cf5Sahrens dmu_objset_close(os); 6861d452cf5Sahrens } 6871d452cf5Sahrens out: 6881d452cf5Sahrens if (err) 6891d452cf5Sahrens (void) strcpy(fsname, sn.failed); 6901d452cf5Sahrens dsl_sync_task_group_destroy(sn.dstg); 6911d452cf5Sahrens spa_close(spa, FTAG); 6921d452cf5Sahrens return (err); 6931d452cf5Sahrens } 6941d452cf5Sahrens 695fa9e4066Sahrens static void 696c717a561Smaybee dmu_objset_sync_dnodes(list_t *list, dmu_tx_t *tx) 697fa9e4066Sahrens { 698c717a561Smaybee dnode_t *dn; 699faafa6e3Sahrens 700c717a561Smaybee while (dn = list_head(list)) { 701c717a561Smaybee ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT); 702c717a561Smaybee ASSERT(dn->dn_dbuf->db_data_pending); 703c717a561Smaybee /* 704c717a561Smaybee * Initialize dn_zio outside dnode_sync() 705c717a561Smaybee * to accomodate meta-dnode 706c717a561Smaybee */ 707c717a561Smaybee dn->dn_zio = dn->dn_dbuf->db_data_pending->dr_zio; 708c717a561Smaybee ASSERT(dn->dn_zio); 709faafa6e3Sahrens 710c717a561Smaybee ASSERT3U(dn->dn_nlevels, <=, DN_MAX_LEVELS); 711c717a561Smaybee list_remove(list, dn); 712c717a561Smaybee dnode_sync(dn, tx); 713fa9e4066Sahrens } 714fa9e4066Sahrens } 715fa9e4066Sahrens 716fa9e4066Sahrens /* ARGSUSED */ 717fa9e4066Sahrens static void 718c717a561Smaybee ready(zio_t *zio, arc_buf_t *abuf, void *arg) 719fa9e4066Sahrens { 720fa9e4066Sahrens objset_impl_t *os = arg; 721c717a561Smaybee blkptr_t *bp = os->os_rootbp; 722c717a561Smaybee dnode_phys_t *dnp = &os->os_phys->os_meta_dnode; 723fa9e4066Sahrens int i; 724fa9e4066Sahrens 725fa9e4066Sahrens /* 726fa9e4066Sahrens * Update rootbp fill count. 727fa9e4066Sahrens */ 728c717a561Smaybee bp->blk_fill = 1; /* count the meta-dnode */ 729fa9e4066Sahrens for (i = 0; i < dnp->dn_nblkptr; i++) 730c717a561Smaybee bp->blk_fill += dnp->dn_blkptr[i].blk_fill; 731c717a561Smaybee } 732c717a561Smaybee 733c717a561Smaybee /* ARGSUSED */ 734c717a561Smaybee static void 735c717a561Smaybee killer(zio_t *zio, arc_buf_t *abuf, void *arg) 736c717a561Smaybee { 737c717a561Smaybee objset_impl_t *os = arg; 738c717a561Smaybee 739c717a561Smaybee ASSERT3U(zio->io_error, ==, 0); 740fa9e4066Sahrens 741fa9e4066Sahrens BP_SET_TYPE(zio->io_bp, DMU_OT_OBJSET); 742fa9e4066Sahrens BP_SET_LEVEL(zio->io_bp, 0); 743fa9e4066Sahrens 744fa9e4066Sahrens if (!DVA_EQUAL(BP_IDENTITY(zio->io_bp), 745fa9e4066Sahrens BP_IDENTITY(&zio->io_bp_orig))) { 746c717a561Smaybee if (zio->io_bp_orig.blk_birth == os->os_synctx->tx_txg) 747c717a561Smaybee dsl_dataset_block_kill(os->os_dsl_dataset, 748c717a561Smaybee &zio->io_bp_orig, NULL, os->os_synctx); 749fa9e4066Sahrens dsl_dataset_block_born(os->os_dsl_dataset, zio->io_bp, 750fa9e4066Sahrens os->os_synctx); 751fa9e4066Sahrens } 752c717a561Smaybee arc_release(os->os_phys_buf, &os->os_phys_buf); 753c717a561Smaybee 754c717a561Smaybee if (os->os_dsl_dataset) 755c717a561Smaybee dmu_buf_rele(os->os_dsl_dataset->ds_dbuf, os->os_dsl_dataset); 756fa9e4066Sahrens } 757fa9e4066Sahrens 758fa9e4066Sahrens /* called from dsl */ 759fa9e4066Sahrens void 760c717a561Smaybee dmu_objset_sync(objset_impl_t *os, zio_t *pio, dmu_tx_t *tx) 761fa9e4066Sahrens { 762fa9e4066Sahrens int txgoff; 763ea8dc4b6Seschrock zbookmark_t zb; 764c717a561Smaybee zio_t *zio; 765c717a561Smaybee list_t *list; 766c717a561Smaybee dbuf_dirty_record_t *dr; 7679bc11082Sek int zio_flags; 768c717a561Smaybee 769c717a561Smaybee dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg); 770fa9e4066Sahrens 771fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 772fa9e4066Sahrens /* XXX the write_done callback should really give us the tx... */ 773fa9e4066Sahrens os->os_synctx = tx; 774fa9e4066Sahrens 775fa9e4066Sahrens /* 776c717a561Smaybee * Create the root block IO 777fa9e4066Sahrens */ 778ea8dc4b6Seschrock zb.zb_objset = os->os_dsl_dataset ? os->os_dsl_dataset->ds_object : 0; 779ea8dc4b6Seschrock zb.zb_object = 0; 780ea8dc4b6Seschrock zb.zb_level = -1; 781ea8dc4b6Seschrock zb.zb_blkid = 0; 7829bc11082Sek zio_flags = ZIO_FLAG_MUSTSUCCEED; 7839bc11082Sek if (dmu_ot[DMU_OT_OBJSET].ot_metadata || zb.zb_level != 0) 7849bc11082Sek zio_flags |= ZIO_FLAG_METADATA; 785c717a561Smaybee if (BP_IS_OLDER(os->os_rootbp, tx->tx_txg)) 786c717a561Smaybee dsl_dataset_block_kill(os->os_dsl_dataset, 787c717a561Smaybee os->os_rootbp, pio, tx); 788c717a561Smaybee zio = arc_write(pio, os->os_spa, os->os_md_checksum, 78944cd46caSbillm os->os_md_compress, 790*d0ad202dSahrens dmu_get_replication_level(os, &zb, DMU_OT_OBJSET), 791c717a561Smaybee tx->tx_txg, os->os_rootbp, os->os_phys_buf, ready, killer, os, 7929bc11082Sek ZIO_PRIORITY_ASYNC_WRITE, zio_flags, &zb); 793c717a561Smaybee 794c717a561Smaybee /* 795c717a561Smaybee * Sync meta-dnode - the parent IO for the sync is the root block 796c717a561Smaybee */ 797c717a561Smaybee os->os_meta_dnode->dn_zio = zio; 798c717a561Smaybee dnode_sync(os->os_meta_dnode, tx); 799c717a561Smaybee 800c717a561Smaybee txgoff = tx->tx_txg & TXG_MASK; 801fa9e4066Sahrens 802c717a561Smaybee dmu_objset_sync_dnodes(&os->os_free_dnodes[txgoff], tx); 803c717a561Smaybee dmu_objset_sync_dnodes(&os->os_dirty_dnodes[txgoff], tx); 804fa9e4066Sahrens 805c717a561Smaybee list = &os->os_meta_dnode->dn_dirty_records[txgoff]; 806c717a561Smaybee while (dr = list_head(list)) { 807c717a561Smaybee ASSERT(dr->dr_dbuf->db_level == 0); 808c717a561Smaybee list_remove(list, dr); 809c717a561Smaybee if (dr->dr_zio) 810c717a561Smaybee zio_nowait(dr->dr_zio); 811c717a561Smaybee } 812c717a561Smaybee /* 813c717a561Smaybee * Free intent log blocks up to this tx. 814c717a561Smaybee */ 815c717a561Smaybee zil_sync(os->os_zil, tx); 816c717a561Smaybee zio_nowait(zio); 817fa9e4066Sahrens } 818fa9e4066Sahrens 819fa9e4066Sahrens void 820a2eea2e1Sahrens dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp, 821a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 822fa9e4066Sahrens { 823a2eea2e1Sahrens dsl_dataset_space(os->os->os_dsl_dataset, refdbytesp, availbytesp, 824a2eea2e1Sahrens usedobjsp, availobjsp); 825a2eea2e1Sahrens } 826a2eea2e1Sahrens 827a2eea2e1Sahrens uint64_t 828a2eea2e1Sahrens dmu_objset_fsid_guid(objset_t *os) 829a2eea2e1Sahrens { 830a2eea2e1Sahrens return (dsl_dataset_fsid_guid(os->os->os_dsl_dataset)); 831a2eea2e1Sahrens } 832a2eea2e1Sahrens 833a2eea2e1Sahrens void 834a2eea2e1Sahrens dmu_objset_fast_stat(objset_t *os, dmu_objset_stats_t *stat) 835a2eea2e1Sahrens { 836a2eea2e1Sahrens stat->dds_type = os->os->os_phys->os_type; 837a2eea2e1Sahrens if (os->os->os_dsl_dataset) 838a2eea2e1Sahrens dsl_dataset_fast_stat(os->os->os_dsl_dataset, stat); 839a2eea2e1Sahrens } 840a2eea2e1Sahrens 841a2eea2e1Sahrens void 842a2eea2e1Sahrens dmu_objset_stats(objset_t *os, nvlist_t *nv) 843a2eea2e1Sahrens { 844a2eea2e1Sahrens ASSERT(os->os->os_dsl_dataset || 845a2eea2e1Sahrens os->os->os_phys->os_type == DMU_OST_META); 846a2eea2e1Sahrens 847a2eea2e1Sahrens if (os->os->os_dsl_dataset != NULL) 848a2eea2e1Sahrens dsl_dataset_stats(os->os->os_dsl_dataset, nv); 849a2eea2e1Sahrens 850a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_TYPE, 851a2eea2e1Sahrens os->os->os_phys->os_type); 852fa9e4066Sahrens } 853fa9e4066Sahrens 854fa9e4066Sahrens int 855fa9e4066Sahrens dmu_objset_is_snapshot(objset_t *os) 856fa9e4066Sahrens { 857fa9e4066Sahrens if (os->os->os_dsl_dataset != NULL) 858fa9e4066Sahrens return (dsl_dataset_is_snapshot(os->os->os_dsl_dataset)); 859fa9e4066Sahrens else 860fa9e4066Sahrens return (B_FALSE); 861fa9e4066Sahrens } 862fa9e4066Sahrens 863fa9e4066Sahrens int 864fa9e4066Sahrens dmu_snapshot_list_next(objset_t *os, int namelen, char *name, 86587e5029aSahrens uint64_t *idp, uint64_t *offp) 866fa9e4066Sahrens { 867fa9e4066Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 868fa9e4066Sahrens zap_cursor_t cursor; 869fa9e4066Sahrens zap_attribute_t attr; 870fa9e4066Sahrens 871fa9e4066Sahrens if (ds->ds_phys->ds_snapnames_zapobj == 0) 872fa9e4066Sahrens return (ENOENT); 873fa9e4066Sahrens 874fa9e4066Sahrens zap_cursor_init_serialized(&cursor, 875fa9e4066Sahrens ds->ds_dir->dd_pool->dp_meta_objset, 876fa9e4066Sahrens ds->ds_phys->ds_snapnames_zapobj, *offp); 877fa9e4066Sahrens 87887e5029aSahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 87987e5029aSahrens zap_cursor_fini(&cursor); 88087e5029aSahrens return (ENOENT); 88187e5029aSahrens } 88287e5029aSahrens 88387e5029aSahrens if (strlen(attr.za_name) + 1 > namelen) { 88487e5029aSahrens zap_cursor_fini(&cursor); 88587e5029aSahrens return (ENAMETOOLONG); 88687e5029aSahrens } 88787e5029aSahrens 88887e5029aSahrens (void) strcpy(name, attr.za_name); 88987e5029aSahrens if (idp) 89087e5029aSahrens *idp = attr.za_first_integer; 89187e5029aSahrens zap_cursor_advance(&cursor); 89287e5029aSahrens *offp = zap_cursor_serialize(&cursor); 89387e5029aSahrens zap_cursor_fini(&cursor); 89487e5029aSahrens 89587e5029aSahrens return (0); 89687e5029aSahrens } 89787e5029aSahrens 89887e5029aSahrens int 89987e5029aSahrens dmu_dir_list_next(objset_t *os, int namelen, char *name, 90087e5029aSahrens uint64_t *idp, uint64_t *offp) 90187e5029aSahrens { 90287e5029aSahrens dsl_dir_t *dd = os->os->os_dsl_dataset->ds_dir; 90387e5029aSahrens zap_cursor_t cursor; 90487e5029aSahrens zap_attribute_t attr; 90587e5029aSahrens 90687e5029aSahrens /* there is no next dir on a snapshot! */ 90787e5029aSahrens if (os->os->os_dsl_dataset->ds_object != 90887e5029aSahrens dd->dd_phys->dd_head_dataset_obj) 909fa9e4066Sahrens return (ENOENT); 910fa9e4066Sahrens 91187e5029aSahrens zap_cursor_init_serialized(&cursor, 91287e5029aSahrens dd->dd_pool->dp_meta_objset, 91387e5029aSahrens dd->dd_phys->dd_child_dir_zapobj, *offp); 91487e5029aSahrens 91587e5029aSahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 91687e5029aSahrens zap_cursor_fini(&cursor); 91787e5029aSahrens return (ENOENT); 91887e5029aSahrens } 91987e5029aSahrens 92087e5029aSahrens if (strlen(attr.za_name) + 1 > namelen) { 92187e5029aSahrens zap_cursor_fini(&cursor); 922fa9e4066Sahrens return (ENAMETOOLONG); 92387e5029aSahrens } 924fa9e4066Sahrens 925fa9e4066Sahrens (void) strcpy(name, attr.za_name); 92687e5029aSahrens if (idp) 92787e5029aSahrens *idp = attr.za_first_integer; 928fa9e4066Sahrens zap_cursor_advance(&cursor); 929fa9e4066Sahrens *offp = zap_cursor_serialize(&cursor); 93087e5029aSahrens zap_cursor_fini(&cursor); 931fa9e4066Sahrens 932fa9e4066Sahrens return (0); 933fa9e4066Sahrens } 934fa9e4066Sahrens 935fa9e4066Sahrens /* 936fa9e4066Sahrens * Find all objsets under name, and for each, call 'func(child_name, arg)'. 937fa9e4066Sahrens */ 9381d452cf5Sahrens int 9391d452cf5Sahrens dmu_objset_find(char *name, int func(char *, void *), void *arg, int flags) 940fa9e4066Sahrens { 941fa9e4066Sahrens dsl_dir_t *dd; 942fa9e4066Sahrens objset_t *os; 943fa9e4066Sahrens uint64_t snapobj; 944fa9e4066Sahrens zap_cursor_t zc; 945fa9e4066Sahrens zap_attribute_t attr; 946fa9e4066Sahrens char *child; 947ea8dc4b6Seschrock int do_self, err; 948fa9e4066Sahrens 949ea8dc4b6Seschrock err = dsl_dir_open(name, FTAG, &dd, NULL); 950ea8dc4b6Seschrock if (err) 9511d452cf5Sahrens return (err); 952fa9e4066Sahrens 9531d452cf5Sahrens /* NB: the $MOS dir doesn't have a head dataset */ 954fa9e4066Sahrens do_self = (dd->dd_phys->dd_head_dataset_obj != 0); 955fa9e4066Sahrens 956fa9e4066Sahrens /* 957fa9e4066Sahrens * Iterate over all children. 958fa9e4066Sahrens */ 9590b69c2f0Sahrens if (flags & DS_FIND_CHILDREN) { 9600b69c2f0Sahrens for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, 9610b69c2f0Sahrens dd->dd_phys->dd_child_dir_zapobj); 9620b69c2f0Sahrens zap_cursor_retrieve(&zc, &attr) == 0; 9630b69c2f0Sahrens (void) zap_cursor_advance(&zc)) { 9640b69c2f0Sahrens ASSERT(attr.za_integer_length == sizeof (uint64_t)); 9650b69c2f0Sahrens ASSERT(attr.za_num_integers == 1); 966fa9e4066Sahrens 9670b69c2f0Sahrens /* 9680b69c2f0Sahrens * No separating '/' because parent's name ends in /. 9690b69c2f0Sahrens */ 9700b69c2f0Sahrens child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 9710b69c2f0Sahrens /* XXX could probably just use name here */ 9720b69c2f0Sahrens dsl_dir_name(dd, child); 9730b69c2f0Sahrens (void) strcat(child, "/"); 9740b69c2f0Sahrens (void) strcat(child, attr.za_name); 9750b69c2f0Sahrens err = dmu_objset_find(child, func, arg, flags); 9760b69c2f0Sahrens kmem_free(child, MAXPATHLEN); 9770b69c2f0Sahrens if (err) 9780b69c2f0Sahrens break; 9790b69c2f0Sahrens } 9800b69c2f0Sahrens zap_cursor_fini(&zc); 9811d452cf5Sahrens 9820b69c2f0Sahrens if (err) { 9830b69c2f0Sahrens dsl_dir_close(dd, FTAG); 9840b69c2f0Sahrens return (err); 9850b69c2f0Sahrens } 986fa9e4066Sahrens } 987fa9e4066Sahrens 988fa9e4066Sahrens /* 989fa9e4066Sahrens * Iterate over all snapshots. 990fa9e4066Sahrens */ 991fa9e4066Sahrens if ((flags & DS_FIND_SNAPSHOTS) && 992fa9e4066Sahrens dmu_objset_open(name, DMU_OST_ANY, 993fa9e4066Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os) == 0) { 994fa9e4066Sahrens 995fa9e4066Sahrens snapobj = os->os->os_dsl_dataset->ds_phys->ds_snapnames_zapobj; 996fa9e4066Sahrens dmu_objset_close(os); 997fa9e4066Sahrens 998fa9e4066Sahrens for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, snapobj); 999fa9e4066Sahrens zap_cursor_retrieve(&zc, &attr) == 0; 1000fa9e4066Sahrens (void) zap_cursor_advance(&zc)) { 1001fa9e4066Sahrens ASSERT(attr.za_integer_length == sizeof (uint64_t)); 1002fa9e4066Sahrens ASSERT(attr.za_num_integers == 1); 1003fa9e4066Sahrens 1004fa9e4066Sahrens child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1005fa9e4066Sahrens /* XXX could probably just use name here */ 1006fa9e4066Sahrens dsl_dir_name(dd, child); 1007fa9e4066Sahrens (void) strcat(child, "@"); 1008fa9e4066Sahrens (void) strcat(child, attr.za_name); 10091d452cf5Sahrens err = func(child, arg); 1010fa9e4066Sahrens kmem_free(child, MAXPATHLEN); 10111d452cf5Sahrens if (err) 10121d452cf5Sahrens break; 1013fa9e4066Sahrens } 101487e5029aSahrens zap_cursor_fini(&zc); 1015fa9e4066Sahrens } 1016fa9e4066Sahrens 1017fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1018fa9e4066Sahrens 10191d452cf5Sahrens if (err) 10201d452cf5Sahrens return (err); 10211d452cf5Sahrens 1022fa9e4066Sahrens /* 1023fa9e4066Sahrens * Apply to self if appropriate. 1024fa9e4066Sahrens */ 1025fa9e4066Sahrens if (do_self) 10261d452cf5Sahrens err = func(name, arg); 10271d452cf5Sahrens return (err); 1028fa9e4066Sahrens } 1029