1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/zfs_context.h> 29 #include <sys/dmu_objset.h> 30 #include <sys/dsl_dir.h> 31 #include <sys/dsl_dataset.h> 32 #include <sys/dsl_prop.h> 33 #include <sys/dsl_pool.h> 34 #include <sys/dnode.h> 35 #include <sys/dbuf.h> 36 #include <sys/dmu_tx.h> 37 #include <sys/zio_checksum.h> 38 #include <sys/zap.h> 39 #include <sys/zil.h> 40 #include <sys/dmu_impl.h> 41 42 43 spa_t * 44 dmu_objset_spa(objset_t *os) 45 { 46 return (os->os->os_spa); 47 } 48 49 zilog_t * 50 dmu_objset_zil(objset_t *os) 51 { 52 return (os->os->os_zil); 53 } 54 55 dsl_pool_t * 56 dmu_objset_pool(objset_t *os) 57 { 58 dsl_dataset_t *ds; 59 60 if ((ds = os->os->os_dsl_dataset) != NULL && ds->ds_dir) 61 return (ds->ds_dir->dd_pool); 62 else 63 return (spa_get_dsl(os->os->os_spa)); 64 } 65 66 dsl_dataset_t * 67 dmu_objset_ds(objset_t *os) 68 { 69 return (os->os->os_dsl_dataset); 70 } 71 72 dmu_objset_type_t 73 dmu_objset_type(objset_t *os) 74 { 75 return (os->os->os_phys->os_type); 76 } 77 78 void 79 dmu_objset_name(objset_t *os, char *buf) 80 { 81 dsl_dataset_name(os->os->os_dsl_dataset, buf); 82 } 83 84 uint64_t 85 dmu_objset_id(objset_t *os) 86 { 87 dsl_dataset_t *ds = os->os->os_dsl_dataset; 88 89 return (ds ? ds->ds_object : 0); 90 } 91 92 static void 93 checksum_changed_cb(void *arg, uint64_t newval) 94 { 95 objset_impl_t *osi = arg; 96 97 /* 98 * Inheritance should have been done by now. 99 */ 100 ASSERT(newval != ZIO_CHECKSUM_INHERIT); 101 102 osi->os_checksum = zio_checksum_select(newval, ZIO_CHECKSUM_ON_VALUE); 103 } 104 105 static void 106 compression_changed_cb(void *arg, uint64_t newval) 107 { 108 objset_impl_t *osi = arg; 109 110 /* 111 * Inheritance and range checking should have been done by now. 112 */ 113 ASSERT(newval != ZIO_COMPRESS_INHERIT); 114 115 osi->os_compress = zio_compress_select(newval, ZIO_COMPRESS_ON_VALUE); 116 } 117 118 void 119 dmu_objset_byteswap(void *buf, size_t size) 120 { 121 objset_phys_t *osp = buf; 122 123 ASSERT(size == sizeof (objset_phys_t)); 124 dnode_byteswap(&osp->os_meta_dnode); 125 byteswap_uint64_array(&osp->os_zil_header, sizeof (zil_header_t)); 126 osp->os_type = BSWAP_64(osp->os_type); 127 } 128 129 int 130 dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 131 objset_impl_t **osip) 132 { 133 objset_impl_t *winner, *osi; 134 int i, err, checksum; 135 136 osi = kmem_zalloc(sizeof (objset_impl_t), KM_SLEEP); 137 osi->os.os = osi; 138 osi->os_dsl_dataset = ds; 139 osi->os_spa = spa; 140 if (bp) 141 osi->os_rootbp = *bp; 142 osi->os_phys = zio_buf_alloc(sizeof (objset_phys_t)); 143 if (!BP_IS_HOLE(&osi->os_rootbp)) { 144 zbookmark_t zb; 145 zb.zb_objset = ds ? ds->ds_object : 0; 146 zb.zb_object = 0; 147 zb.zb_level = -1; 148 zb.zb_blkid = 0; 149 150 dprintf_bp(&osi->os_rootbp, "reading %s", ""); 151 err = arc_read(NULL, spa, &osi->os_rootbp, 152 dmu_ot[DMU_OT_OBJSET].ot_byteswap, 153 arc_bcopy_func, osi->os_phys, 154 ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, ARC_WAIT, &zb); 155 if (err) { 156 zio_buf_free(osi->os_phys, sizeof (objset_phys_t)); 157 kmem_free(osi, sizeof (objset_impl_t)); 158 return (err); 159 } 160 } else { 161 bzero(osi->os_phys, sizeof (objset_phys_t)); 162 } 163 164 /* 165 * Note: the changed_cb will be called once before the register 166 * func returns, thus changing the checksum/compression from the 167 * default (fletcher2/off). 168 */ 169 if (ds) { 170 err = dsl_prop_register(ds, "checksum", 171 checksum_changed_cb, osi); 172 if (err == 0) 173 err = dsl_prop_register(ds, "compression", 174 compression_changed_cb, osi); 175 if (err) { 176 zio_buf_free(osi->os_phys, sizeof (objset_phys_t)); 177 kmem_free(osi, sizeof (objset_impl_t)); 178 return (err); 179 } 180 } else { 181 /* It's the meta-objset. */ 182 osi->os_checksum = ZIO_CHECKSUM_FLETCHER_4; 183 osi->os_compress = ZIO_COMPRESS_LZJB; 184 } 185 186 osi->os_zil = zil_alloc(&osi->os, &osi->os_phys->os_zil_header); 187 188 /* 189 * Metadata always gets compressed and checksummed. 190 * If the data checksum is multi-bit correctable, and it's not 191 * a ZBT-style checksum, then it's suitable for metadata as well. 192 * Otherwise, the metadata checksum defaults to fletcher4. 193 */ 194 checksum = osi->os_checksum; 195 196 if (zio_checksum_table[checksum].ci_correctable && 197 !zio_checksum_table[checksum].ci_zbt) 198 osi->os_md_checksum = checksum; 199 else 200 osi->os_md_checksum = ZIO_CHECKSUM_FLETCHER_4; 201 osi->os_md_compress = ZIO_COMPRESS_LZJB; 202 203 for (i = 0; i < TXG_SIZE; i++) { 204 list_create(&osi->os_dirty_dnodes[i], sizeof (dnode_t), 205 offsetof(dnode_t, dn_dirty_link[i])); 206 list_create(&osi->os_free_dnodes[i], sizeof (dnode_t), 207 offsetof(dnode_t, dn_dirty_link[i])); 208 } 209 list_create(&osi->os_dnodes, sizeof (dnode_t), 210 offsetof(dnode_t, dn_link)); 211 list_create(&osi->os_downgraded_dbufs, sizeof (dmu_buf_impl_t), 212 offsetof(dmu_buf_impl_t, db_link)); 213 214 osi->os_meta_dnode = dnode_special_open(osi, 215 &osi->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT); 216 217 if (ds != NULL) { 218 winner = dsl_dataset_set_user_ptr(ds, osi, dmu_objset_evict); 219 if (winner) { 220 dmu_objset_evict(ds, osi); 221 osi = winner; 222 } 223 } 224 225 *osip = osi; 226 return (0); 227 } 228 229 /* called from zpl */ 230 int 231 dmu_objset_open(const char *name, dmu_objset_type_t type, int mode, 232 objset_t **osp) 233 { 234 dsl_dataset_t *ds; 235 int err; 236 objset_t *os; 237 objset_impl_t *osi; 238 239 os = kmem_alloc(sizeof (objset_t), KM_SLEEP); 240 err = dsl_dataset_open(name, mode, os, &ds); 241 if (err) { 242 kmem_free(os, sizeof (objset_t)); 243 return (err); 244 } 245 246 osi = dsl_dataset_get_user_ptr(ds); 247 if (osi == NULL) { 248 blkptr_t bp; 249 250 dsl_dataset_get_blkptr(ds, &bp); 251 err = dmu_objset_open_impl(dsl_dataset_get_spa(ds), 252 ds, &bp, &osi); 253 if (err) { 254 dsl_dataset_close(ds, mode, os); 255 kmem_free(os, sizeof (objset_t)); 256 return (err); 257 } 258 } 259 260 os->os = osi; 261 os->os_mode = mode; 262 263 if (type != DMU_OST_ANY && type != os->os->os_phys->os_type) { 264 dmu_objset_close(os); 265 return (EINVAL); 266 } 267 *osp = os; 268 return (0); 269 } 270 271 void 272 dmu_objset_close(objset_t *os) 273 { 274 dsl_dataset_close(os->os->os_dsl_dataset, os->os_mode, os); 275 kmem_free(os, sizeof (objset_t)); 276 } 277 278 void 279 dmu_objset_evict_dbufs(objset_t *os) 280 { 281 objset_impl_t *osi = os->os; 282 dnode_t *mdn = osi->os_meta_dnode; 283 dnode_t *dn; 284 int allzero = B_TRUE; 285 286 /* 287 * Each time we process an entry on the list, we first move it 288 * to the tail so that we don't process it over and over again. 289 * We use the meta-dnode as a marker: if we make a complete pass 290 * over the list without finding any work to do, we're done. 291 * This ensures that we complete in linear time rather than 292 * quadratic time, as described in detail in bug 1182169. 293 */ 294 mutex_enter(&osi->os_lock); 295 list_remove(&osi->os_dnodes, mdn); 296 list_insert_tail(&osi->os_dnodes, mdn); 297 while ((dn = list_head(&osi->os_dnodes)) != NULL) { 298 list_remove(&osi->os_dnodes, dn); 299 list_insert_tail(&osi->os_dnodes, dn); 300 if (dn == mdn) { 301 if (allzero) 302 break; 303 allzero = B_TRUE; 304 continue; 305 } 306 if (!refcount_is_zero(&dn->dn_holds)) { 307 allzero = B_FALSE; 308 dnode_add_ref(dn, FTAG); 309 mutex_exit(&osi->os_lock); 310 dnode_evict_dbufs(dn); 311 dnode_rele(dn, FTAG); 312 mutex_enter(&osi->os_lock); 313 } 314 } 315 mutex_exit(&osi->os_lock); 316 dnode_evict_dbufs(mdn); 317 } 318 319 void 320 dmu_objset_evict(dsl_dataset_t *ds, void *arg) 321 { 322 objset_impl_t *osi = arg; 323 objset_t os; 324 int err, i; 325 326 for (i = 0; i < TXG_SIZE; i++) { 327 ASSERT(list_head(&osi->os_dirty_dnodes[i]) == NULL); 328 ASSERT(list_head(&osi->os_free_dnodes[i]) == NULL); 329 } 330 331 if (ds) { 332 err = dsl_prop_unregister(ds, "checksum", 333 checksum_changed_cb, osi); 334 ASSERT(err == 0); 335 336 err = dsl_prop_unregister(ds, "compression", 337 compression_changed_cb, osi); 338 ASSERT(err == 0); 339 } 340 341 /* 342 * We should need only a single pass over the dnode list, since 343 * nothing can be added to the list at this point. 344 */ 345 os.os = osi; 346 dmu_objset_evict_dbufs(&os); 347 348 ASSERT3P(list_head(&osi->os_dnodes), ==, osi->os_meta_dnode); 349 ASSERT3P(list_tail(&osi->os_dnodes), ==, osi->os_meta_dnode); 350 ASSERT3P(list_head(&osi->os_meta_dnode->dn_dbufs), ==, NULL); 351 352 dnode_special_close(osi->os_meta_dnode); 353 zil_free(osi->os_zil); 354 355 zio_buf_free(osi->os_phys, sizeof (objset_phys_t)); 356 kmem_free(osi, sizeof (objset_impl_t)); 357 } 358 359 /* called from dsl for meta-objset */ 360 objset_impl_t * 361 dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, dmu_objset_type_t type, 362 dmu_tx_t *tx) 363 { 364 objset_impl_t *osi; 365 dnode_t *mdn; 366 367 ASSERT(dmu_tx_is_syncing(tx)); 368 VERIFY(0 == dmu_objset_open_impl(spa, ds, NULL, &osi)); 369 mdn = osi->os_meta_dnode; 370 371 dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT, 372 DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx); 373 374 /* 375 * We don't want to have to increase the meta-dnode's nlevels 376 * later, because then we could do it in quescing context while 377 * we are also accessing it in open context. 378 * 379 * This precaution is not necessary for the MOS (ds == NULL), 380 * because the MOS is only updated in syncing context. 381 * This is most fortunate: the MOS is the only objset that 382 * needs to be synced multiple times as spa_sync() iterates 383 * to convergence, so minimizing its dn_nlevels matters. 384 */ 385 if (ds != NULL) { 386 int levels = 1; 387 388 /* 389 * Determine the number of levels necessary for the meta-dnode 390 * to contain DN_MAX_OBJECT dnodes. 391 */ 392 while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift + 393 (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) < 394 DN_MAX_OBJECT * sizeof (dnode_phys_t)) 395 levels++; 396 397 mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = 398 mdn->dn_nlevels = levels; 399 } 400 401 ASSERT(type != DMU_OST_NONE); 402 ASSERT(type != DMU_OST_ANY); 403 ASSERT(type < DMU_OST_NUMTYPES); 404 osi->os_phys->os_type = type; 405 406 dsl_dataset_dirty(ds, tx); 407 408 return (osi); 409 } 410 411 struct oscarg { 412 void (*userfunc)(objset_t *os, void *arg, dmu_tx_t *tx); 413 void *userarg; 414 dsl_dataset_t *clone_parent; 415 const char *fullname; 416 const char *lastname; 417 dmu_objset_type_t type; 418 }; 419 420 static int 421 dmu_objset_create_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 422 { 423 struct oscarg *oa = arg; 424 dsl_dataset_t *ds; 425 int err; 426 blkptr_t bp; 427 428 ASSERT(dmu_tx_is_syncing(tx)); 429 430 err = dsl_dataset_create_sync(dd, oa->fullname, oa->lastname, 431 oa->clone_parent, tx); 432 dprintf_dd(dd, "fn=%s ln=%s err=%d\n", 433 oa->fullname, oa->lastname, err); 434 if (err) 435 return (err); 436 437 VERIFY(0 == dsl_dataset_open_spa(dd->dd_pool->dp_spa, oa->fullname, 438 DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ds)); 439 dsl_dataset_get_blkptr(ds, &bp); 440 if (BP_IS_HOLE(&bp)) { 441 objset_impl_t *osi; 442 443 /* This is an empty dmu_objset; not a clone. */ 444 osi = dmu_objset_create_impl(dsl_dataset_get_spa(ds), 445 ds, oa->type, tx); 446 447 if (oa->userfunc) 448 oa->userfunc(&osi->os, oa->userarg, tx); 449 } 450 dsl_dataset_close(ds, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG); 451 452 return (0); 453 } 454 455 int 456 dmu_objset_create(const char *name, dmu_objset_type_t type, 457 objset_t *clone_parent, 458 void (*func)(objset_t *os, void *arg, dmu_tx_t *tx), void *arg) 459 { 460 dsl_dir_t *pds; 461 const char *tail; 462 int err = 0; 463 464 err = dsl_dir_open(name, FTAG, &pds, &tail); 465 if (err) 466 return (err); 467 if (tail == NULL) { 468 dsl_dir_close(pds, FTAG); 469 return (EEXIST); 470 } 471 472 dprintf("name=%s\n", name); 473 474 if (tail[0] == '@') { 475 /* 476 * If we're creating a snapshot, make sure everything 477 * they might want is on disk. XXX Sketchy to know 478 * about snapshots here, better to put in DSL. 479 */ 480 objset_t *os; 481 size_t plen = strchr(name, '@') - name + 1; 482 char *pbuf = kmem_alloc(plen, KM_SLEEP); 483 bcopy(name, pbuf, plen - 1); 484 pbuf[plen - 1] = '\0'; 485 486 err = dmu_objset_open(pbuf, DMU_OST_ANY, DS_MODE_STANDARD, &os); 487 if (err == 0) { 488 err = zil_suspend(dmu_objset_zil(os)); 489 if (err == 0) { 490 err = dsl_dir_sync_task(pds, 491 dsl_dataset_snapshot_sync, 492 (void*)(tail+1), 16*1024); 493 zil_resume(dmu_objset_zil(os)); 494 } 495 dmu_objset_close(os); 496 } 497 kmem_free(pbuf, plen); 498 } else { 499 struct oscarg oa = { 0 }; 500 oa.userfunc = func; 501 oa.userarg = arg; 502 oa.fullname = name; 503 oa.lastname = tail; 504 oa.type = type; 505 if (clone_parent != NULL) { 506 /* 507 * You can't clone to a different type. 508 */ 509 if (clone_parent->os->os_phys->os_type != type) { 510 dsl_dir_close(pds, FTAG); 511 return (EINVAL); 512 } 513 oa.clone_parent = clone_parent->os->os_dsl_dataset; 514 } 515 err = dsl_dir_sync_task(pds, dmu_objset_create_sync, &oa, 516 256*1024); 517 } 518 dsl_dir_close(pds, FTAG); 519 return (err); 520 } 521 522 int 523 dmu_objset_destroy(const char *name) 524 { 525 objset_t *os; 526 int error; 527 528 /* 529 * If it looks like we'll be able to destroy it, and there's 530 * an unplayed replay log sitting around, destroy the log. 531 * It would be nicer to do this in dsl_dataset_destroy_sync(), 532 * but the replay log objset is modified in open context. 533 */ 534 error = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 535 if (error == 0) { 536 zil_destroy(dmu_objset_zil(os)); 537 dmu_objset_close(os); 538 } 539 540 /* XXX uncache everything? */ 541 return (dsl_dataset_destroy(name)); 542 } 543 544 int 545 dmu_objset_rollback(const char *name) 546 { 547 int err; 548 objset_t *os; 549 550 err = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 551 if (err == 0) { 552 err = zil_suspend(dmu_objset_zil(os)); 553 if (err == 0) 554 zil_resume(dmu_objset_zil(os)); 555 dmu_objset_close(os); 556 if (err == 0) { 557 /* XXX uncache everything? */ 558 err = dsl_dataset_rollback(name); 559 } 560 } 561 return (err); 562 } 563 564 static void 565 dmu_objset_sync_dnodes(objset_impl_t *os, list_t *list, dmu_tx_t *tx) 566 { 567 dnode_t *dn = list_head(list); 568 int level, err; 569 570 for (level = 0; dn = list_head(list); level++) { 571 zio_t *zio; 572 zio = zio_root(os->os_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 573 574 ASSERT3U(level, <=, DN_MAX_LEVELS); 575 576 while (dn) { 577 dnode_t *next = list_next(list, dn); 578 579 list_remove(list, dn); 580 if (dnode_sync(dn, level, zio, tx) == 0) { 581 /* 582 * This dnode requires syncing at higher 583 * levels; put it back onto the list. 584 */ 585 if (next) 586 list_insert_before(list, next, dn); 587 else 588 list_insert_tail(list, dn); 589 } 590 dn = next; 591 } 592 err = zio_wait(zio); 593 ASSERT(err == 0); 594 } 595 } 596 597 /* ARGSUSED */ 598 static void 599 killer(zio_t *zio, arc_buf_t *abuf, void *arg) 600 { 601 objset_impl_t *os = arg; 602 objset_phys_t *osphys = zio->io_data; 603 dnode_phys_t *dnp = &osphys->os_meta_dnode; 604 int i; 605 606 ASSERT3U(zio->io_error, ==, 0); 607 608 /* 609 * Update rootbp fill count. 610 */ 611 os->os_rootbp.blk_fill = 1; /* count the meta-dnode */ 612 for (i = 0; i < dnp->dn_nblkptr; i++) 613 os->os_rootbp.blk_fill += dnp->dn_blkptr[i].blk_fill; 614 615 BP_SET_TYPE(zio->io_bp, DMU_OT_OBJSET); 616 BP_SET_LEVEL(zio->io_bp, 0); 617 618 if (!DVA_EQUAL(BP_IDENTITY(zio->io_bp), 619 BP_IDENTITY(&zio->io_bp_orig))) { 620 dsl_dataset_block_kill(os->os_dsl_dataset, &zio->io_bp_orig, 621 os->os_synctx); 622 dsl_dataset_block_born(os->os_dsl_dataset, zio->io_bp, 623 os->os_synctx); 624 } 625 } 626 627 628 /* called from dsl */ 629 void 630 dmu_objset_sync(objset_impl_t *os, dmu_tx_t *tx) 631 { 632 extern taskq_t *dbuf_tq; 633 int txgoff; 634 list_t *dirty_list; 635 int err; 636 zbookmark_t zb; 637 arc_buf_t *abuf = 638 arc_buf_alloc(os->os_spa, sizeof (objset_phys_t), FTAG); 639 640 ASSERT(dmu_tx_is_syncing(tx)); 641 ASSERT(os->os_synctx == NULL); 642 /* XXX the write_done callback should really give us the tx... */ 643 os->os_synctx = tx; 644 645 dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg); 646 647 txgoff = tx->tx_txg & TXG_MASK; 648 649 dmu_objset_sync_dnodes(os, &os->os_free_dnodes[txgoff], tx); 650 dmu_objset_sync_dnodes(os, &os->os_dirty_dnodes[txgoff], tx); 651 652 /* 653 * Free intent log blocks up to this tx. 654 */ 655 zil_sync(os->os_zil, tx); 656 657 /* 658 * Sync meta-dnode 659 */ 660 dirty_list = &os->os_dirty_dnodes[txgoff]; 661 ASSERT(list_head(dirty_list) == NULL); 662 list_insert_tail(dirty_list, os->os_meta_dnode); 663 dmu_objset_sync_dnodes(os, dirty_list, tx); 664 665 /* 666 * Sync the root block. 667 */ 668 bcopy(os->os_phys, abuf->b_data, sizeof (objset_phys_t)); 669 zb.zb_objset = os->os_dsl_dataset ? os->os_dsl_dataset->ds_object : 0; 670 zb.zb_object = 0; 671 zb.zb_level = -1; 672 zb.zb_blkid = 0; 673 err = arc_write(NULL, os->os_spa, os->os_md_checksum, 674 os->os_md_compress, tx->tx_txg, &os->os_rootbp, abuf, killer, os, 675 ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, ARC_WAIT, &zb); 676 ASSERT(err == 0); 677 VERIFY(arc_buf_remove_ref(abuf, FTAG) == 1); 678 679 dsl_dataset_set_blkptr(os->os_dsl_dataset, &os->os_rootbp, tx); 680 681 ASSERT3P(os->os_synctx, ==, tx); 682 taskq_wait(dbuf_tq); 683 os->os_synctx = NULL; 684 } 685 686 void 687 dmu_objset_stats(objset_t *os, dmu_objset_stats_t *dds) 688 { 689 if (os->os->os_dsl_dataset != NULL) { 690 dsl_dataset_stats(os->os->os_dsl_dataset, dds); 691 } else { 692 ASSERT(os->os->os_phys->os_type == DMU_OST_META); 693 bzero(dds, sizeof (*dds)); 694 } 695 dds->dds_type = os->os->os_phys->os_type; 696 } 697 698 int 699 dmu_objset_is_snapshot(objset_t *os) 700 { 701 if (os->os->os_dsl_dataset != NULL) 702 return (dsl_dataset_is_snapshot(os->os->os_dsl_dataset)); 703 else 704 return (B_FALSE); 705 } 706 707 int 708 dmu_snapshot_list_next(objset_t *os, int namelen, char *name, 709 uint64_t *idp, uint64_t *offp) 710 { 711 dsl_dataset_t *ds = os->os->os_dsl_dataset; 712 zap_cursor_t cursor; 713 zap_attribute_t attr; 714 715 if (ds->ds_phys->ds_snapnames_zapobj == 0) 716 return (ENOENT); 717 718 zap_cursor_init_serialized(&cursor, 719 ds->ds_dir->dd_pool->dp_meta_objset, 720 ds->ds_phys->ds_snapnames_zapobj, *offp); 721 722 if (zap_cursor_retrieve(&cursor, &attr) != 0) { 723 zap_cursor_fini(&cursor); 724 return (ENOENT); 725 } 726 727 if (strlen(attr.za_name) + 1 > namelen) { 728 zap_cursor_fini(&cursor); 729 return (ENAMETOOLONG); 730 } 731 732 (void) strcpy(name, attr.za_name); 733 if (idp) 734 *idp = attr.za_first_integer; 735 zap_cursor_advance(&cursor); 736 *offp = zap_cursor_serialize(&cursor); 737 zap_cursor_fini(&cursor); 738 739 return (0); 740 } 741 742 int 743 dmu_dir_list_next(objset_t *os, int namelen, char *name, 744 uint64_t *idp, uint64_t *offp) 745 { 746 dsl_dir_t *dd = os->os->os_dsl_dataset->ds_dir; 747 zap_cursor_t cursor; 748 zap_attribute_t attr; 749 750 if (dd->dd_phys->dd_child_dir_zapobj == 0) 751 return (ENOENT); 752 753 /* there is no next dir on a snapshot! */ 754 if (os->os->os_dsl_dataset->ds_object != 755 dd->dd_phys->dd_head_dataset_obj) 756 return (ENOENT); 757 758 zap_cursor_init_serialized(&cursor, 759 dd->dd_pool->dp_meta_objset, 760 dd->dd_phys->dd_child_dir_zapobj, *offp); 761 762 if (zap_cursor_retrieve(&cursor, &attr) != 0) { 763 zap_cursor_fini(&cursor); 764 return (ENOENT); 765 } 766 767 if (strlen(attr.za_name) + 1 > namelen) { 768 zap_cursor_fini(&cursor); 769 return (ENAMETOOLONG); 770 } 771 772 (void) strcpy(name, attr.za_name); 773 if (idp) 774 *idp = attr.za_first_integer; 775 zap_cursor_advance(&cursor); 776 *offp = zap_cursor_serialize(&cursor); 777 zap_cursor_fini(&cursor); 778 779 return (0); 780 } 781 782 /* 783 * Find all objsets under name, and for each, call 'func(child_name, arg)'. 784 */ 785 void 786 dmu_objset_find(char *name, void func(char *, void *), void *arg, int flags) 787 { 788 dsl_dir_t *dd; 789 objset_t *os; 790 uint64_t snapobj; 791 zap_cursor_t zc; 792 zap_attribute_t attr; 793 char *child; 794 int do_self, err; 795 796 err = dsl_dir_open(name, FTAG, &dd, NULL); 797 if (err) 798 return; 799 800 do_self = (dd->dd_phys->dd_head_dataset_obj != 0); 801 802 /* 803 * Iterate over all children. 804 */ 805 if (dd->dd_phys->dd_child_dir_zapobj != 0) { 806 for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, 807 dd->dd_phys->dd_child_dir_zapobj); 808 zap_cursor_retrieve(&zc, &attr) == 0; 809 (void) zap_cursor_advance(&zc)) { 810 ASSERT(attr.za_integer_length == sizeof (uint64_t)); 811 ASSERT(attr.za_num_integers == 1); 812 813 /* 814 * No separating '/' because parent's name ends in /. 815 */ 816 child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 817 /* XXX could probably just use name here */ 818 dsl_dir_name(dd, child); 819 (void) strcat(child, "/"); 820 (void) strcat(child, attr.za_name); 821 dmu_objset_find(child, func, arg, flags); 822 kmem_free(child, MAXPATHLEN); 823 } 824 zap_cursor_fini(&zc); 825 } 826 827 /* 828 * Iterate over all snapshots. 829 */ 830 if ((flags & DS_FIND_SNAPSHOTS) && 831 dmu_objset_open(name, DMU_OST_ANY, 832 DS_MODE_STANDARD | DS_MODE_READONLY, &os) == 0) { 833 834 snapobj = os->os->os_dsl_dataset->ds_phys->ds_snapnames_zapobj; 835 dmu_objset_close(os); 836 837 for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, snapobj); 838 zap_cursor_retrieve(&zc, &attr) == 0; 839 (void) zap_cursor_advance(&zc)) { 840 ASSERT(attr.za_integer_length == sizeof (uint64_t)); 841 ASSERT(attr.za_num_integers == 1); 842 843 child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 844 /* XXX could probably just use name here */ 845 dsl_dir_name(dd, child); 846 (void) strcat(child, "@"); 847 (void) strcat(child, attr.za_name); 848 func(child, arg); 849 kmem_free(child, MAXPATHLEN); 850 } 851 zap_cursor_fini(&zc); 852 } 853 854 dsl_dir_close(dd, FTAG); 855 856 /* 857 * Apply to self if appropriate. 858 */ 859 if (do_self) 860 func(name, arg); 861 } 862