1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5789Sahrens * Common Development and Distribution License, Version 1.0 only 6789Sahrens * (the "License"). You may not use this file except in compliance 7789Sahrens * with the License. 8789Sahrens * 9789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10789Sahrens * or http://www.opensolaris.org/os/licensing. 11789Sahrens * See the License for the specific language governing permissions 12789Sahrens * and limitations under the License. 13789Sahrens * 14789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19789Sahrens * 20789Sahrens * CDDL HEADER END 21789Sahrens */ 22789Sahrens /* 23789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens #include <sys/zfs_context.h> 30789Sahrens #include <sys/dmu_objset.h> 31789Sahrens #include <sys/dsl_dir.h> 32789Sahrens #include <sys/dsl_dataset.h> 33789Sahrens #include <sys/dsl_prop.h> 34789Sahrens #include <sys/dsl_pool.h> 35789Sahrens #include <sys/dnode.h> 36789Sahrens #include <sys/dbuf.h> 37789Sahrens #include <sys/dmu_tx.h> 38789Sahrens #include <sys/zio_checksum.h> 39789Sahrens #include <sys/zap.h> 40789Sahrens #include <sys/zil.h> 41789Sahrens #include <sys/dmu_impl.h> 42789Sahrens 43789Sahrens 44789Sahrens spa_t * 45789Sahrens dmu_objset_spa(objset_t *os) 46789Sahrens { 47789Sahrens return (os->os->os_spa); 48789Sahrens } 49789Sahrens 50789Sahrens zilog_t * 51789Sahrens dmu_objset_zil(objset_t *os) 52789Sahrens { 53789Sahrens return (os->os->os_zil); 54789Sahrens } 55789Sahrens 56789Sahrens dsl_pool_t * 57789Sahrens dmu_objset_pool(objset_t *os) 58789Sahrens { 59789Sahrens dsl_dataset_t *ds; 60789Sahrens 61789Sahrens if ((ds = os->os->os_dsl_dataset) != NULL && ds->ds_dir) 62789Sahrens return (ds->ds_dir->dd_pool); 63789Sahrens else 64789Sahrens return (spa_get_dsl(os->os->os_spa)); 65789Sahrens } 66789Sahrens 67789Sahrens dsl_dataset_t * 68789Sahrens dmu_objset_ds(objset_t *os) 69789Sahrens { 70789Sahrens return (os->os->os_dsl_dataset); 71789Sahrens } 72789Sahrens 73789Sahrens dmu_objset_type_t 74789Sahrens dmu_objset_type(objset_t *os) 75789Sahrens { 76789Sahrens return (os->os->os_phys->os_type); 77789Sahrens } 78789Sahrens 79789Sahrens void 80789Sahrens dmu_objset_name(objset_t *os, char *buf) 81789Sahrens { 82789Sahrens dsl_dataset_name(os->os->os_dsl_dataset, buf); 83789Sahrens } 84789Sahrens 85789Sahrens uint64_t 86789Sahrens dmu_objset_id(objset_t *os) 87789Sahrens { 88789Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 89789Sahrens 90789Sahrens return (ds ? ds->ds_object : 0); 91789Sahrens } 92789Sahrens 93789Sahrens static void 94789Sahrens checksum_changed_cb(void *arg, uint64_t newval) 95789Sahrens { 96789Sahrens objset_impl_t *osi = arg; 97789Sahrens 98789Sahrens /* 99789Sahrens * Inheritance should have been done by now. 100789Sahrens */ 101789Sahrens ASSERT(newval != ZIO_CHECKSUM_INHERIT); 102789Sahrens 103789Sahrens osi->os_checksum = zio_checksum_select(newval, ZIO_CHECKSUM_ON_VALUE); 104789Sahrens } 105789Sahrens 106789Sahrens static void 107789Sahrens compression_changed_cb(void *arg, uint64_t newval) 108789Sahrens { 109789Sahrens objset_impl_t *osi = arg; 110789Sahrens 111789Sahrens /* 112789Sahrens * Inheritance and range checking should have been done by now. 113789Sahrens */ 114789Sahrens ASSERT(newval != ZIO_COMPRESS_INHERIT); 115789Sahrens 116789Sahrens osi->os_compress = zio_compress_select(newval, ZIO_COMPRESS_ON_VALUE); 117789Sahrens } 118789Sahrens 119789Sahrens void 120789Sahrens dmu_objset_byteswap(void *buf, size_t size) 121789Sahrens { 122789Sahrens objset_phys_t *osp = buf; 123789Sahrens 124789Sahrens ASSERT(size == sizeof (objset_phys_t)); 125789Sahrens dnode_byteswap(&osp->os_meta_dnode); 126789Sahrens byteswap_uint64_array(&osp->os_zil_header, sizeof (zil_header_t)); 127789Sahrens osp->os_type = BSWAP_64(osp->os_type); 128789Sahrens } 129789Sahrens 130789Sahrens objset_impl_t * 131789Sahrens dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp) 132789Sahrens { 133789Sahrens objset_impl_t *winner, *osi; 134789Sahrens int i, err, checksum; 135789Sahrens 136789Sahrens osi = kmem_zalloc(sizeof (objset_impl_t), KM_SLEEP); 137789Sahrens osi->os.os = osi; 138789Sahrens osi->os_dsl_dataset = ds; 139789Sahrens osi->os_spa = spa; 140789Sahrens if (bp) 141789Sahrens osi->os_rootbp = *bp; 142789Sahrens osi->os_phys = zio_buf_alloc(sizeof (objset_phys_t)); 143789Sahrens if (!BP_IS_HOLE(&osi->os_rootbp)) { 144789Sahrens dprintf_bp(&osi->os_rootbp, "reading %s", ""); 145789Sahrens (void) arc_read(NULL, spa, &osi->os_rootbp, 146789Sahrens dmu_ot[DMU_OT_OBJSET].ot_byteswap, 147789Sahrens arc_bcopy_func, osi->os_phys, 148789Sahrens ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_MUSTSUCCEED, ARC_WAIT); 149789Sahrens } else { 150789Sahrens bzero(osi->os_phys, sizeof (objset_phys_t)); 151789Sahrens } 152789Sahrens osi->os_zil = zil_alloc(&osi->os, &osi->os_phys->os_zil_header); 153789Sahrens 154789Sahrens /* 155789Sahrens * Note: the changed_cb will be called once before the register 156789Sahrens * func returns, thus changing the checksum/compression from the 157789Sahrens * default (fletcher2/off). 158789Sahrens */ 159789Sahrens if (ds) { 160789Sahrens err = dsl_prop_register(ds, "checksum", 161789Sahrens checksum_changed_cb, osi); 162789Sahrens ASSERT(err == 0); 163789Sahrens 164789Sahrens err = dsl_prop_register(ds, "compression", 165789Sahrens compression_changed_cb, osi); 166789Sahrens ASSERT(err == 0); 167789Sahrens } else { 168789Sahrens /* It's the meta-objset. */ 169789Sahrens osi->os_checksum = ZIO_CHECKSUM_FLETCHER_4; 170789Sahrens osi->os_compress = ZIO_COMPRESS_LZJB; 171789Sahrens } 172789Sahrens 173789Sahrens /* 174789Sahrens * Metadata always gets compressed and checksummed. 175789Sahrens * If the data checksum is multi-bit correctable, and it's not 176789Sahrens * a ZBT-style checksum, then it's suitable for metadata as well. 177789Sahrens * Otherwise, the metadata checksum defaults to fletcher4. 178789Sahrens */ 179789Sahrens checksum = osi->os_checksum; 180789Sahrens 181789Sahrens if (zio_checksum_table[checksum].ci_correctable && 182789Sahrens !zio_checksum_table[checksum].ci_zbt) 183789Sahrens osi->os_md_checksum = checksum; 184789Sahrens else 185789Sahrens osi->os_md_checksum = ZIO_CHECKSUM_FLETCHER_4; 186789Sahrens 187789Sahrens osi->os_md_compress = ZIO_COMPRESS_LZJB; 188789Sahrens 189789Sahrens for (i = 0; i < TXG_SIZE; i++) { 190789Sahrens list_create(&osi->os_dirty_dnodes[i], sizeof (dnode_t), 191789Sahrens offsetof(dnode_t, dn_dirty_link[i])); 192789Sahrens list_create(&osi->os_free_dnodes[i], sizeof (dnode_t), 193789Sahrens offsetof(dnode_t, dn_dirty_link[i])); 194789Sahrens } 195789Sahrens list_create(&osi->os_dnodes, sizeof (dnode_t), 196789Sahrens offsetof(dnode_t, dn_link)); 197789Sahrens list_create(&osi->os_downgraded_dbufs, sizeof (dmu_buf_impl_t), 198789Sahrens offsetof(dmu_buf_impl_t, db_link)); 199789Sahrens 200789Sahrens osi->os_meta_dnode = dnode_special_open(osi, 201789Sahrens &osi->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT); 202789Sahrens 203789Sahrens if (ds != NULL) { 204789Sahrens winner = dsl_dataset_set_user_ptr(ds, osi, dmu_objset_evict); 205789Sahrens if (winner) { 206789Sahrens dmu_objset_evict(ds, osi); 207789Sahrens osi = winner; 208789Sahrens } 209789Sahrens } 210789Sahrens 211789Sahrens return (osi); 212789Sahrens } 213789Sahrens 214789Sahrens /* called from zpl */ 215789Sahrens int 216789Sahrens dmu_objset_open(const char *name, dmu_objset_type_t type, int mode, 217789Sahrens objset_t **osp) 218789Sahrens { 219789Sahrens dsl_dataset_t *ds; 220789Sahrens int err; 221789Sahrens objset_t *os; 222789Sahrens objset_impl_t *osi; 223789Sahrens 224789Sahrens os = kmem_alloc(sizeof (objset_t), KM_SLEEP); 225789Sahrens err = dsl_dataset_open(name, mode, os, &ds); 226789Sahrens if (err) { 227789Sahrens kmem_free(os, sizeof (objset_t)); 228789Sahrens return (err); 229789Sahrens } 230789Sahrens 231789Sahrens osi = dsl_dataset_get_user_ptr(ds); 232789Sahrens if (osi == NULL) { 233789Sahrens blkptr_t bp; 234789Sahrens 235789Sahrens dsl_dataset_get_blkptr(ds, &bp); 236789Sahrens osi = dmu_objset_open_impl(dsl_dataset_get_spa(ds), ds, &bp); 237789Sahrens } 238789Sahrens 239789Sahrens os->os = osi; 240789Sahrens os->os_mode = mode; 241789Sahrens 242789Sahrens if (type != DMU_OST_ANY && type != os->os->os_phys->os_type) { 243789Sahrens dmu_objset_close(os); 244789Sahrens return (EINVAL); 245789Sahrens } 246789Sahrens *osp = os; 247789Sahrens return (0); 248789Sahrens } 249789Sahrens 250789Sahrens void 251789Sahrens dmu_objset_close(objset_t *os) 252789Sahrens { 253789Sahrens dsl_dataset_close(os->os->os_dsl_dataset, os->os_mode, os); 254789Sahrens kmem_free(os, sizeof (objset_t)); 255789Sahrens } 256789Sahrens 257789Sahrens void 258789Sahrens dmu_objset_evict(dsl_dataset_t *ds, void *arg) 259789Sahrens { 260789Sahrens objset_impl_t *osi = arg; 261789Sahrens int err, i; 262789Sahrens 263789Sahrens for (i = 0; i < TXG_SIZE; i++) { 264789Sahrens ASSERT(list_head(&osi->os_dirty_dnodes[i]) == NULL); 265789Sahrens ASSERT(list_head(&osi->os_free_dnodes[i]) == NULL); 266789Sahrens } 267789Sahrens 268789Sahrens if (ds) { 269789Sahrens err = dsl_prop_unregister(ds, "checksum", 270789Sahrens checksum_changed_cb, osi); 271789Sahrens ASSERT(err == 0); 272789Sahrens 273789Sahrens err = dsl_prop_unregister(ds, "compression", 274789Sahrens compression_changed_cb, osi); 275789Sahrens ASSERT(err == 0); 276789Sahrens } 277789Sahrens 278789Sahrens ASSERT3P(list_head(&osi->os_dnodes), ==, osi->os_meta_dnode); 279789Sahrens ASSERT3P(list_tail(&osi->os_dnodes), ==, osi->os_meta_dnode); 280789Sahrens ASSERT3P(list_head(&osi->os_meta_dnode->dn_dbufs), ==, NULL); 281789Sahrens 282789Sahrens dnode_special_close(osi->os_meta_dnode); 283789Sahrens zil_free(osi->os_zil); 284789Sahrens 285789Sahrens zio_buf_free(osi->os_phys, sizeof (objset_phys_t)); 286789Sahrens kmem_free(osi, sizeof (objset_impl_t)); 287789Sahrens } 288789Sahrens 289789Sahrens /* called from dsl for meta-objset */ 290789Sahrens objset_impl_t * 291789Sahrens dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, dmu_objset_type_t type, 292789Sahrens dmu_tx_t *tx) 293789Sahrens { 294789Sahrens objset_impl_t *osi; 295789Sahrens dnode_t *mdn; 296789Sahrens 297789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 298789Sahrens osi = dmu_objset_open_impl(spa, ds, NULL); 299789Sahrens mdn = osi->os_meta_dnode; 300789Sahrens 301789Sahrens dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT, 302789Sahrens DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx); 303789Sahrens 304789Sahrens /* 305789Sahrens * We don't want to have to increase the meta-dnode's nlevels 306789Sahrens * later, because then we could do it in quescing context while 307789Sahrens * we are also accessing it in open context. 308789Sahrens * 309789Sahrens * This precaution is not necessary for the MOS (ds == NULL), 310789Sahrens * because the MOS is only updated in syncing context. 311789Sahrens * This is most fortunate: the MOS is the only objset that 312789Sahrens * needs to be synced multiple times as spa_sync() iterates 313789Sahrens * to convergence, so minimizing its dn_nlevels matters. 314789Sahrens */ 315789Sahrens if (ds != NULL) 316789Sahrens mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = 317789Sahrens mdn->dn_nlevels = DN_META_DNODE_LEVELS; 318789Sahrens 319789Sahrens ASSERT(type != DMU_OST_NONE); 320789Sahrens ASSERT(type != DMU_OST_ANY); 321789Sahrens ASSERT(type < DMU_OST_NUMTYPES); 322789Sahrens osi->os_phys->os_type = type; 323789Sahrens 324789Sahrens dsl_dataset_dirty(ds, tx); 325789Sahrens 326789Sahrens return (osi); 327789Sahrens } 328789Sahrens 329789Sahrens struct oscarg { 330789Sahrens void (*userfunc)(objset_t *os, void *arg, dmu_tx_t *tx); 331789Sahrens void *userarg; 332789Sahrens dsl_dataset_t *clone_parent; 333789Sahrens const char *fullname; 334789Sahrens const char *lastname; 335789Sahrens dmu_objset_type_t type; 336789Sahrens }; 337789Sahrens 338789Sahrens static int 339789Sahrens dmu_objset_create_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 340789Sahrens { 341789Sahrens struct oscarg *oa = arg; 342789Sahrens dsl_dataset_t *ds; 343789Sahrens int err; 344789Sahrens blkptr_t bp; 345789Sahrens 346789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 347789Sahrens 348789Sahrens err = dsl_dataset_create_sync(dd, oa->fullname, oa->lastname, 349789Sahrens oa->clone_parent, tx); 350789Sahrens dprintf_dd(dd, "fn=%s ln=%s err=%d\n", 351789Sahrens oa->fullname, oa->lastname, err); 352789Sahrens if (err) 353789Sahrens return (err); 354789Sahrens 355789Sahrens err = dsl_dataset_open_spa(dd->dd_pool->dp_spa, oa->fullname, 356789Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ds); 357789Sahrens ASSERT3U(err, ==, 0); 358789Sahrens dsl_dataset_get_blkptr(ds, &bp); 359789Sahrens if (BP_IS_HOLE(&bp)) { 360789Sahrens objset_impl_t *osi; 361789Sahrens 362789Sahrens /* This is an empty dmu_objset; not a clone. */ 363789Sahrens osi = dmu_objset_create_impl(dsl_dataset_get_spa(ds), 364789Sahrens ds, oa->type, tx); 365789Sahrens 366789Sahrens if (oa->userfunc) 367789Sahrens oa->userfunc(&osi->os, oa->userarg, tx); 368789Sahrens } 369789Sahrens dsl_dataset_close(ds, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG); 370789Sahrens 371789Sahrens return (0); 372789Sahrens } 373789Sahrens 374789Sahrens int 375789Sahrens dmu_objset_create(const char *name, dmu_objset_type_t type, 376789Sahrens objset_t *clone_parent, 377789Sahrens void (*func)(objset_t *os, void *arg, dmu_tx_t *tx), void *arg) 378789Sahrens { 379789Sahrens dsl_dir_t *pds; 380789Sahrens const char *tail; 381789Sahrens int err = 0; 382789Sahrens 383789Sahrens pds = dsl_dir_open(name, FTAG, &tail); 384789Sahrens if (pds == NULL) 385789Sahrens return (ENOENT); 386789Sahrens if (tail == NULL) { 387789Sahrens dsl_dir_close(pds, FTAG); 388789Sahrens return (EEXIST); 389789Sahrens } 390789Sahrens 391789Sahrens dprintf("name=%s\n", name); 392789Sahrens 393789Sahrens if (tail[0] == '@') { 394789Sahrens /* 395789Sahrens * If we're creating a snapshot, make sure everything 396789Sahrens * they might want is on disk. XXX Sketchy to know 397789Sahrens * about snapshots here, better to put in DSL. 398789Sahrens */ 399789Sahrens objset_t *os; 400789Sahrens size_t plen = strchr(name, '@') - name + 1; 401789Sahrens char *pbuf = kmem_alloc(plen, KM_SLEEP); 402789Sahrens bcopy(name, pbuf, plen - 1); 403789Sahrens pbuf[plen - 1] = '\0'; 404789Sahrens 405789Sahrens err = dmu_objset_open(pbuf, DMU_OST_ANY, DS_MODE_STANDARD, &os); 406789Sahrens if (err == 0) { 407789Sahrens err = zil_suspend(dmu_objset_zil(os)); 408789Sahrens if (err == 0) { 409789Sahrens err = dsl_dir_sync_task(pds, 410789Sahrens dsl_dataset_snapshot_sync, 411789Sahrens (void*)(tail+1), 16*1024); 412789Sahrens zil_resume(dmu_objset_zil(os)); 413789Sahrens } 414789Sahrens dmu_objset_close(os); 415789Sahrens } 416789Sahrens kmem_free(pbuf, plen); 417789Sahrens } else { 418789Sahrens struct oscarg oa = { 0 }; 419789Sahrens oa.userfunc = func; 420789Sahrens oa.userarg = arg; 421789Sahrens oa.fullname = name; 422789Sahrens oa.lastname = tail; 423789Sahrens oa.type = type; 424789Sahrens if (clone_parent != NULL) { 425789Sahrens /* 426789Sahrens * You can't clone to a different type. 427789Sahrens */ 428789Sahrens if (clone_parent->os->os_phys->os_type != type) { 429789Sahrens dsl_dir_close(pds, FTAG); 430789Sahrens return (EINVAL); 431789Sahrens } 432789Sahrens oa.clone_parent = clone_parent->os->os_dsl_dataset; 433789Sahrens } 434789Sahrens err = dsl_dir_sync_task(pds, dmu_objset_create_sync, &oa, 435789Sahrens 256*1024); 436789Sahrens } 437789Sahrens dsl_dir_close(pds, FTAG); 438789Sahrens return (err); 439789Sahrens } 440789Sahrens 441789Sahrens int 442789Sahrens dmu_objset_destroy(const char *name) 443789Sahrens { 444789Sahrens objset_t *os; 445789Sahrens int error; 446789Sahrens 447789Sahrens /* 448789Sahrens * If it looks like we'll be able to destroy it, and there's 449789Sahrens * an unplayed replay log sitting around, destroy the log. 450789Sahrens * It would be nicer to do this in dsl_dataset_destroy_sync(), 451789Sahrens * but the replay log objset is modified in open context. 452789Sahrens */ 453789Sahrens error = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 454789Sahrens if (error == 0) { 455789Sahrens zil_destroy(dmu_objset_zil(os)); 456789Sahrens dmu_objset_close(os); 457789Sahrens } 458789Sahrens 459789Sahrens /* XXX uncache everything? */ 460789Sahrens return (dsl_dataset_destroy(name)); 461789Sahrens } 462789Sahrens 463789Sahrens int 464789Sahrens dmu_objset_rollback(const char *name) 465789Sahrens { 466789Sahrens int err; 467789Sahrens objset_t *os; 468789Sahrens 469789Sahrens err = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 470789Sahrens if (err == 0) { 471789Sahrens err = zil_suspend(dmu_objset_zil(os)); 472789Sahrens if (err == 0) 473789Sahrens zil_resume(dmu_objset_zil(os)); 474789Sahrens dmu_objset_close(os); 475789Sahrens if (err == 0) { 476789Sahrens /* XXX uncache everything? */ 477789Sahrens err = dsl_dataset_rollback(name); 478789Sahrens } 479789Sahrens } 480789Sahrens return (err); 481789Sahrens } 482789Sahrens 483789Sahrens static void 484789Sahrens dmu_objset_sync_dnodes(objset_impl_t *os, list_t *list, dmu_tx_t *tx) 485789Sahrens { 486789Sahrens dnode_t *dn = list_head(list); 487789Sahrens int level, err; 488789Sahrens 489789Sahrens for (level = 0; dn = list_head(list); level++) { 490789Sahrens zio_t *zio; 491789Sahrens zio = zio_root(os->os_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 492789Sahrens 493789Sahrens ASSERT3U(level, <=, DN_MAX_LEVELS); 494789Sahrens 495789Sahrens while (dn) { 496789Sahrens dnode_t *next = list_next(list, dn); 497789Sahrens 498789Sahrens list_remove(list, dn); 499789Sahrens if (dnode_sync(dn, level, zio, tx) == 0) { 500789Sahrens /* 501789Sahrens * This dnode requires syncing at higher 502789Sahrens * levels; put it back onto the list. 503789Sahrens */ 504789Sahrens if (next) 505789Sahrens list_insert_before(list, next, dn); 506789Sahrens else 507789Sahrens list_insert_tail(list, dn); 508789Sahrens } 509789Sahrens dn = next; 510789Sahrens } 511789Sahrens err = zio_wait(zio); 512789Sahrens ASSERT(err == 0); 513789Sahrens } 514789Sahrens } 515789Sahrens 516789Sahrens /* ARGSUSED */ 517789Sahrens static void 518789Sahrens killer(zio_t *zio, arc_buf_t *abuf, void *arg) 519789Sahrens { 520789Sahrens objset_impl_t *os = arg; 521789Sahrens objset_phys_t *osphys = zio->io_data; 522789Sahrens dnode_phys_t *dnp = &osphys->os_meta_dnode; 523789Sahrens int i; 524789Sahrens 525789Sahrens ASSERT3U(zio->io_error, ==, 0); 526789Sahrens 527789Sahrens /* 528789Sahrens * Update rootbp fill count. 529789Sahrens */ 530789Sahrens os->os_rootbp.blk_fill = 1; /* count the meta-dnode */ 531789Sahrens for (i = 0; i < dnp->dn_nblkptr; i++) 532789Sahrens os->os_rootbp.blk_fill += dnp->dn_blkptr[i].blk_fill; 533789Sahrens 534789Sahrens BP_SET_TYPE(zio->io_bp, DMU_OT_OBJSET); 535789Sahrens BP_SET_LEVEL(zio->io_bp, 0); 536789Sahrens 537789Sahrens if (!DVA_EQUAL(BP_IDENTITY(zio->io_bp), 538789Sahrens BP_IDENTITY(&zio->io_bp_orig))) { 539789Sahrens dsl_dataset_block_kill(os->os_dsl_dataset, &zio->io_bp_orig, 540789Sahrens os->os_synctx); 541789Sahrens dsl_dataset_block_born(os->os_dsl_dataset, zio->io_bp, 542789Sahrens os->os_synctx); 543789Sahrens } 544789Sahrens } 545789Sahrens 546789Sahrens 547789Sahrens /* called from dsl */ 548789Sahrens void 549789Sahrens dmu_objset_sync(objset_impl_t *os, dmu_tx_t *tx) 550789Sahrens { 551789Sahrens extern taskq_t *dbuf_tq; 552789Sahrens int txgoff; 553789Sahrens list_t *dirty_list; 554789Sahrens int err; 555789Sahrens arc_buf_t *abuf = 556789Sahrens arc_buf_alloc(os->os_spa, sizeof (objset_phys_t), FTAG); 557789Sahrens 558789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 559789Sahrens ASSERT(os->os_synctx == NULL); 560789Sahrens /* XXX the write_done callback should really give us the tx... */ 561789Sahrens os->os_synctx = tx; 562789Sahrens 563789Sahrens dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg); 564789Sahrens 565789Sahrens txgoff = tx->tx_txg & TXG_MASK; 566789Sahrens 567789Sahrens dmu_objset_sync_dnodes(os, &os->os_free_dnodes[txgoff], tx); 568789Sahrens dmu_objset_sync_dnodes(os, &os->os_dirty_dnodes[txgoff], tx); 569789Sahrens 570789Sahrens /* 571789Sahrens * Free intent log blocks up to this tx. 572789Sahrens */ 573789Sahrens zil_sync(os->os_zil, tx); 574789Sahrens 575789Sahrens /* 576789Sahrens * Sync meta-dnode 577789Sahrens */ 578789Sahrens dirty_list = &os->os_dirty_dnodes[txgoff]; 579789Sahrens ASSERT(list_head(dirty_list) == NULL); 580789Sahrens list_insert_tail(dirty_list, os->os_meta_dnode); 581789Sahrens dmu_objset_sync_dnodes(os, dirty_list, tx); 582789Sahrens 583789Sahrens /* 584789Sahrens * Sync the root block. 585789Sahrens */ 586789Sahrens bcopy(os->os_phys, abuf->b_data, sizeof (objset_phys_t)); 587789Sahrens err = arc_write(NULL, os->os_spa, os->os_md_checksum, 588789Sahrens os->os_md_compress, tx->tx_txg, &os->os_rootbp, abuf, killer, os, 589789Sahrens ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, ARC_WAIT); 590789Sahrens ASSERT(err == 0); 591789Sahrens arc_buf_free(abuf, FTAG); 592789Sahrens 593789Sahrens dsl_dataset_set_blkptr(os->os_dsl_dataset, &os->os_rootbp, tx); 594789Sahrens 595789Sahrens ASSERT3P(os->os_synctx, ==, tx); 596789Sahrens taskq_wait(dbuf_tq); 597789Sahrens os->os_synctx = NULL; 598789Sahrens } 599789Sahrens 600789Sahrens void 601789Sahrens dmu_objset_stats(objset_t *os, dmu_objset_stats_t *dds) 602789Sahrens { 603789Sahrens if (os->os->os_dsl_dataset != NULL) { 604789Sahrens dsl_dataset_stats(os->os->os_dsl_dataset, dds); 605789Sahrens } else { 606789Sahrens ASSERT(os->os->os_phys->os_type == DMU_OST_META); 607789Sahrens bzero(dds, sizeof (*dds)); 608789Sahrens } 609789Sahrens dds->dds_type = os->os->os_phys->os_type; 610789Sahrens } 611789Sahrens 612789Sahrens int 613789Sahrens dmu_objset_is_snapshot(objset_t *os) 614789Sahrens { 615789Sahrens if (os->os->os_dsl_dataset != NULL) 616789Sahrens return (dsl_dataset_is_snapshot(os->os->os_dsl_dataset)); 617789Sahrens else 618789Sahrens return (B_FALSE); 619789Sahrens } 620789Sahrens 621789Sahrens int 622789Sahrens dmu_snapshot_list_next(objset_t *os, int namelen, char *name, 623*885Sahrens uint64_t *idp, uint64_t *offp) 624789Sahrens { 625789Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 626789Sahrens zap_cursor_t cursor; 627789Sahrens zap_attribute_t attr; 628789Sahrens 629789Sahrens if (ds->ds_phys->ds_snapnames_zapobj == 0) 630789Sahrens return (ENOENT); 631789Sahrens 632789Sahrens zap_cursor_init_serialized(&cursor, 633789Sahrens ds->ds_dir->dd_pool->dp_meta_objset, 634789Sahrens ds->ds_phys->ds_snapnames_zapobj, *offp); 635789Sahrens 636*885Sahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 637*885Sahrens zap_cursor_fini(&cursor); 638*885Sahrens return (ENOENT); 639*885Sahrens } 640*885Sahrens 641*885Sahrens if (strlen(attr.za_name) + 1 > namelen) { 642*885Sahrens zap_cursor_fini(&cursor); 643*885Sahrens return (ENAMETOOLONG); 644*885Sahrens } 645*885Sahrens 646*885Sahrens (void) strcpy(name, attr.za_name); 647*885Sahrens if (idp) 648*885Sahrens *idp = attr.za_first_integer; 649*885Sahrens zap_cursor_advance(&cursor); 650*885Sahrens *offp = zap_cursor_serialize(&cursor); 651*885Sahrens zap_cursor_fini(&cursor); 652*885Sahrens 653*885Sahrens return (0); 654*885Sahrens } 655*885Sahrens 656*885Sahrens int 657*885Sahrens dmu_dir_list_next(objset_t *os, int namelen, char *name, 658*885Sahrens uint64_t *idp, uint64_t *offp) 659*885Sahrens { 660*885Sahrens dsl_dir_t *dd = os->os->os_dsl_dataset->ds_dir; 661*885Sahrens zap_cursor_t cursor; 662*885Sahrens zap_attribute_t attr; 663*885Sahrens 664*885Sahrens if (dd->dd_phys->dd_child_dir_zapobj == 0) 665789Sahrens return (ENOENT); 666789Sahrens 667*885Sahrens /* there is no next dir on a snapshot! */ 668*885Sahrens if (os->os->os_dsl_dataset->ds_object != 669*885Sahrens dd->dd_phys->dd_head_dataset_obj) 670*885Sahrens return (ENOENT); 671*885Sahrens 672*885Sahrens zap_cursor_init_serialized(&cursor, 673*885Sahrens dd->dd_pool->dp_meta_objset, 674*885Sahrens dd->dd_phys->dd_child_dir_zapobj, *offp); 675*885Sahrens 676*885Sahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 677*885Sahrens zap_cursor_fini(&cursor); 678*885Sahrens return (ENOENT); 679*885Sahrens } 680*885Sahrens 681*885Sahrens if (strlen(attr.za_name) + 1 > namelen) { 682*885Sahrens zap_cursor_fini(&cursor); 683789Sahrens return (ENAMETOOLONG); 684*885Sahrens } 685789Sahrens 686789Sahrens (void) strcpy(name, attr.za_name); 687*885Sahrens if (idp) 688*885Sahrens *idp = attr.za_first_integer; 689789Sahrens zap_cursor_advance(&cursor); 690789Sahrens *offp = zap_cursor_serialize(&cursor); 691*885Sahrens zap_cursor_fini(&cursor); 692789Sahrens 693789Sahrens return (0); 694789Sahrens } 695789Sahrens 696789Sahrens /* 697789Sahrens * Find all objsets under name, and for each, call 'func(child_name, arg)'. 698789Sahrens */ 699789Sahrens void 700789Sahrens dmu_objset_find(char *name, void func(char *, void *), void *arg, int flags) 701789Sahrens { 702789Sahrens dsl_dir_t *dd; 703789Sahrens objset_t *os; 704789Sahrens uint64_t snapobj; 705789Sahrens zap_cursor_t zc; 706789Sahrens zap_attribute_t attr; 707789Sahrens char *child; 708789Sahrens int do_self; 709789Sahrens 710789Sahrens dd = dsl_dir_open(name, FTAG, NULL); 711789Sahrens if (dd == NULL) 712789Sahrens return; 713789Sahrens 714789Sahrens do_self = (dd->dd_phys->dd_head_dataset_obj != 0); 715789Sahrens 716789Sahrens /* 717789Sahrens * Iterate over all children. 718789Sahrens */ 719789Sahrens if (dd->dd_phys->dd_child_dir_zapobj != 0) { 720789Sahrens for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, 721789Sahrens dd->dd_phys->dd_child_dir_zapobj); 722789Sahrens zap_cursor_retrieve(&zc, &attr) == 0; 723789Sahrens (void) zap_cursor_advance(&zc)) { 724789Sahrens ASSERT(attr.za_integer_length == sizeof (uint64_t)); 725789Sahrens ASSERT(attr.za_num_integers == 1); 726789Sahrens 727789Sahrens /* 728789Sahrens * No separating '/' because parent's name ends in /. 729789Sahrens */ 730789Sahrens child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 731789Sahrens /* XXX could probably just use name here */ 732789Sahrens dsl_dir_name(dd, child); 733789Sahrens (void) strcat(child, "/"); 734789Sahrens (void) strcat(child, attr.za_name); 735789Sahrens dmu_objset_find(child, func, arg, flags); 736789Sahrens kmem_free(child, MAXPATHLEN); 737789Sahrens } 738*885Sahrens zap_cursor_fini(&zc); 739789Sahrens } 740789Sahrens 741789Sahrens /* 742789Sahrens * Iterate over all snapshots. 743789Sahrens */ 744789Sahrens if ((flags & DS_FIND_SNAPSHOTS) && 745789Sahrens dmu_objset_open(name, DMU_OST_ANY, 746789Sahrens DS_MODE_STANDARD | DS_MODE_READONLY, &os) == 0) { 747789Sahrens 748789Sahrens snapobj = os->os->os_dsl_dataset->ds_phys->ds_snapnames_zapobj; 749789Sahrens dmu_objset_close(os); 750789Sahrens 751789Sahrens for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, snapobj); 752789Sahrens zap_cursor_retrieve(&zc, &attr) == 0; 753789Sahrens (void) zap_cursor_advance(&zc)) { 754789Sahrens ASSERT(attr.za_integer_length == sizeof (uint64_t)); 755789Sahrens ASSERT(attr.za_num_integers == 1); 756789Sahrens 757789Sahrens child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 758789Sahrens /* XXX could probably just use name here */ 759789Sahrens dsl_dir_name(dd, child); 760789Sahrens (void) strcat(child, "@"); 761789Sahrens (void) strcat(child, attr.za_name); 762789Sahrens func(child, arg); 763789Sahrens kmem_free(child, MAXPATHLEN); 764789Sahrens } 765*885Sahrens zap_cursor_fini(&zc); 766789Sahrens } 767789Sahrens 768789Sahrens dsl_dir_close(dd, FTAG); 769789Sahrens 770789Sahrens /* 771789Sahrens * Apply to self if appropriate. 772789Sahrens */ 773789Sahrens if (do_self) 774789Sahrens func(name, arg); 775789Sahrens } 776