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 *dn; 283 284 mutex_enter(&osi->os_lock); 285 286 /* process the mdn last, since the other dnodes have holds on it */ 287 list_remove(&osi->os_dnodes, osi->os_meta_dnode); 288 list_insert_tail(&osi->os_dnodes, osi->os_meta_dnode); 289 290 /* 291 * Find the first dnode with holds. We have to do this dance 292 * because dnode_add_ref() only works if you already have a 293 * hold. If there are no holds then it has no dbufs so OK to 294 * skip. 295 */ 296 for (dn = list_head(&osi->os_dnodes); 297 dn && refcount_is_zero(&dn->dn_holds); 298 dn = list_next(&osi->os_dnodes, dn)) 299 continue; 300 if (dn) 301 dnode_add_ref(dn, FTAG); 302 303 while (dn) { 304 dnode_t *next_dn = dn; 305 306 do { 307 next_dn = list_next(&osi->os_dnodes, next_dn); 308 } while (next_dn && refcount_is_zero(&next_dn->dn_holds)); 309 if (next_dn) 310 dnode_add_ref(next_dn, FTAG); 311 312 mutex_exit(&osi->os_lock); 313 dnode_evict_dbufs(dn); 314 dnode_rele(dn, FTAG); 315 mutex_enter(&osi->os_lock); 316 dn = next_dn; 317 } 318 mutex_exit(&osi->os_lock); 319 } 320 321 void 322 dmu_objset_evict(dsl_dataset_t *ds, void *arg) 323 { 324 objset_impl_t *osi = arg; 325 objset_t os; 326 int err, i; 327 328 for (i = 0; i < TXG_SIZE; i++) { 329 ASSERT(list_head(&osi->os_dirty_dnodes[i]) == NULL); 330 ASSERT(list_head(&osi->os_free_dnodes[i]) == NULL); 331 } 332 333 if (ds) { 334 err = dsl_prop_unregister(ds, "checksum", 335 checksum_changed_cb, osi); 336 ASSERT(err == 0); 337 338 err = dsl_prop_unregister(ds, "compression", 339 compression_changed_cb, osi); 340 ASSERT(err == 0); 341 } 342 343 /* 344 * We should need only a single pass over the dnode list, since 345 * nothing can be added to the list at this point. 346 */ 347 os.os = osi; 348 dmu_objset_evict_dbufs(&os); 349 350 ASSERT3P(list_head(&osi->os_dnodes), ==, osi->os_meta_dnode); 351 ASSERT3P(list_tail(&osi->os_dnodes), ==, osi->os_meta_dnode); 352 ASSERT3P(list_head(&osi->os_meta_dnode->dn_dbufs), ==, NULL); 353 354 dnode_special_close(osi->os_meta_dnode); 355 zil_free(osi->os_zil); 356 357 zio_buf_free(osi->os_phys, sizeof (objset_phys_t)); 358 kmem_free(osi, sizeof (objset_impl_t)); 359 } 360 361 /* called from dsl for meta-objset */ 362 objset_impl_t * 363 dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, dmu_objset_type_t type, 364 dmu_tx_t *tx) 365 { 366 objset_impl_t *osi; 367 dnode_t *mdn; 368 369 ASSERT(dmu_tx_is_syncing(tx)); 370 VERIFY(0 == dmu_objset_open_impl(spa, ds, NULL, &osi)); 371 mdn = osi->os_meta_dnode; 372 373 dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT, 374 DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx); 375 376 /* 377 * We don't want to have to increase the meta-dnode's nlevels 378 * later, because then we could do it in quescing context while 379 * we are also accessing it in open context. 380 * 381 * This precaution is not necessary for the MOS (ds == NULL), 382 * because the MOS is only updated in syncing context. 383 * This is most fortunate: the MOS is the only objset that 384 * needs to be synced multiple times as spa_sync() iterates 385 * to convergence, so minimizing its dn_nlevels matters. 386 */ 387 if (ds != NULL) { 388 int levels = 1; 389 390 /* 391 * Determine the number of levels necessary for the meta-dnode 392 * to contain DN_MAX_OBJECT dnodes. 393 */ 394 while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift + 395 (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) < 396 DN_MAX_OBJECT * sizeof (dnode_phys_t)) 397 levels++; 398 399 mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = 400 mdn->dn_nlevels = levels; 401 } 402 403 ASSERT(type != DMU_OST_NONE); 404 ASSERT(type != DMU_OST_ANY); 405 ASSERT(type < DMU_OST_NUMTYPES); 406 osi->os_phys->os_type = type; 407 408 dsl_dataset_dirty(ds, tx); 409 410 return (osi); 411 } 412 413 struct oscarg { 414 void (*userfunc)(objset_t *os, void *arg, dmu_tx_t *tx); 415 void *userarg; 416 dsl_dataset_t *clone_parent; 417 const char *fullname; 418 const char *lastname; 419 dmu_objset_type_t type; 420 }; 421 422 static int 423 dmu_objset_create_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 424 { 425 struct oscarg *oa = arg; 426 dsl_dataset_t *ds; 427 int err; 428 blkptr_t bp; 429 430 ASSERT(dmu_tx_is_syncing(tx)); 431 432 err = dsl_dataset_create_sync(dd, oa->fullname, oa->lastname, 433 oa->clone_parent, tx); 434 dprintf_dd(dd, "fn=%s ln=%s err=%d\n", 435 oa->fullname, oa->lastname, err); 436 if (err) 437 return (err); 438 439 VERIFY(0 == dsl_dataset_open_spa(dd->dd_pool->dp_spa, oa->fullname, 440 DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ds)); 441 dsl_dataset_get_blkptr(ds, &bp); 442 if (BP_IS_HOLE(&bp)) { 443 objset_impl_t *osi; 444 445 /* This is an empty dmu_objset; not a clone. */ 446 osi = dmu_objset_create_impl(dsl_dataset_get_spa(ds), 447 ds, oa->type, tx); 448 449 if (oa->userfunc) 450 oa->userfunc(&osi->os, oa->userarg, tx); 451 } 452 dsl_dataset_close(ds, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG); 453 454 return (0); 455 } 456 457 int 458 dmu_objset_create(const char *name, dmu_objset_type_t type, 459 objset_t *clone_parent, 460 void (*func)(objset_t *os, void *arg, dmu_tx_t *tx), void *arg) 461 { 462 dsl_dir_t *pds; 463 const char *tail; 464 int err = 0; 465 466 err = dsl_dir_open(name, FTAG, &pds, &tail); 467 if (err) 468 return (err); 469 if (tail == NULL) { 470 dsl_dir_close(pds, FTAG); 471 return (EEXIST); 472 } 473 474 dprintf("name=%s\n", name); 475 476 if (tail[0] == '@') { 477 /* 478 * If we're creating a snapshot, make sure everything 479 * they might want is on disk. XXX Sketchy to know 480 * about snapshots here, better to put in DSL. 481 */ 482 objset_t *os; 483 size_t plen = strchr(name, '@') - name + 1; 484 char *pbuf = kmem_alloc(plen, KM_SLEEP); 485 bcopy(name, pbuf, plen - 1); 486 pbuf[plen - 1] = '\0'; 487 488 err = dmu_objset_open(pbuf, DMU_OST_ANY, DS_MODE_STANDARD, &os); 489 if (err == 0) { 490 err = zil_suspend(dmu_objset_zil(os)); 491 if (err == 0) { 492 err = dsl_dir_sync_task(pds, 493 dsl_dataset_snapshot_sync, 494 (void*)(tail+1), 16*1024); 495 zil_resume(dmu_objset_zil(os)); 496 } 497 dmu_objset_close(os); 498 } 499 kmem_free(pbuf, plen); 500 } else { 501 struct oscarg oa = { 0 }; 502 oa.userfunc = func; 503 oa.userarg = arg; 504 oa.fullname = name; 505 oa.lastname = tail; 506 oa.type = type; 507 if (clone_parent != NULL) { 508 /* 509 * You can't clone to a different type. 510 */ 511 if (clone_parent->os->os_phys->os_type != type) { 512 dsl_dir_close(pds, FTAG); 513 return (EINVAL); 514 } 515 oa.clone_parent = clone_parent->os->os_dsl_dataset; 516 } 517 err = dsl_dir_sync_task(pds, dmu_objset_create_sync, &oa, 518 256*1024); 519 } 520 dsl_dir_close(pds, FTAG); 521 return (err); 522 } 523 524 int 525 dmu_objset_destroy(const char *name) 526 { 527 objset_t *os; 528 int error; 529 530 /* 531 * If it looks like we'll be able to destroy it, and there's 532 * an unplayed replay log sitting around, destroy the log. 533 * It would be nicer to do this in dsl_dataset_destroy_sync(), 534 * but the replay log objset is modified in open context. 535 */ 536 error = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 537 if (error == 0) { 538 zil_destroy(dmu_objset_zil(os)); 539 dmu_objset_close(os); 540 } 541 542 /* XXX uncache everything? */ 543 return (dsl_dataset_destroy(name)); 544 } 545 546 int 547 dmu_objset_rollback(const char *name) 548 { 549 int err; 550 objset_t *os; 551 552 err = dmu_objset_open(name, DMU_OST_ANY, DS_MODE_EXCLUSIVE, &os); 553 if (err == 0) { 554 err = zil_suspend(dmu_objset_zil(os)); 555 if (err == 0) 556 zil_resume(dmu_objset_zil(os)); 557 dmu_objset_close(os); 558 if (err == 0) { 559 /* XXX uncache everything? */ 560 err = dsl_dataset_rollback(name); 561 } 562 } 563 return (err); 564 } 565 566 static void 567 dmu_objset_sync_dnodes(objset_impl_t *os, list_t *list, dmu_tx_t *tx) 568 { 569 dnode_t *dn = list_head(list); 570 int level, err; 571 572 for (level = 0; dn = list_head(list); level++) { 573 zio_t *zio; 574 zio = zio_root(os->os_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 575 576 ASSERT3U(level, <=, DN_MAX_LEVELS); 577 578 while (dn) { 579 dnode_t *next = list_next(list, dn); 580 581 list_remove(list, dn); 582 if (dnode_sync(dn, level, zio, tx) == 0) { 583 /* 584 * This dnode requires syncing at higher 585 * levels; put it back onto the list. 586 */ 587 if (next) 588 list_insert_before(list, next, dn); 589 else 590 list_insert_tail(list, dn); 591 } 592 dn = next; 593 } 594 err = zio_wait(zio); 595 ASSERT(err == 0); 596 } 597 } 598 599 /* ARGSUSED */ 600 static void 601 killer(zio_t *zio, arc_buf_t *abuf, void *arg) 602 { 603 objset_impl_t *os = arg; 604 objset_phys_t *osphys = zio->io_data; 605 dnode_phys_t *dnp = &osphys->os_meta_dnode; 606 int i; 607 608 ASSERT3U(zio->io_error, ==, 0); 609 610 /* 611 * Update rootbp fill count. 612 */ 613 os->os_rootbp.blk_fill = 1; /* count the meta-dnode */ 614 for (i = 0; i < dnp->dn_nblkptr; i++) 615 os->os_rootbp.blk_fill += dnp->dn_blkptr[i].blk_fill; 616 617 BP_SET_TYPE(zio->io_bp, DMU_OT_OBJSET); 618 BP_SET_LEVEL(zio->io_bp, 0); 619 620 if (!DVA_EQUAL(BP_IDENTITY(zio->io_bp), 621 BP_IDENTITY(&zio->io_bp_orig))) { 622 dsl_dataset_block_kill(os->os_dsl_dataset, &zio->io_bp_orig, 623 os->os_synctx); 624 dsl_dataset_block_born(os->os_dsl_dataset, zio->io_bp, 625 os->os_synctx); 626 } 627 } 628 629 630 /* called from dsl */ 631 void 632 dmu_objset_sync(objset_impl_t *os, dmu_tx_t *tx) 633 { 634 extern taskq_t *dbuf_tq; 635 int txgoff; 636 list_t *dirty_list; 637 int err; 638 zbookmark_t zb; 639 arc_buf_t *abuf = 640 arc_buf_alloc(os->os_spa, sizeof (objset_phys_t), FTAG); 641 642 ASSERT(dmu_tx_is_syncing(tx)); 643 ASSERT(os->os_synctx == NULL); 644 /* XXX the write_done callback should really give us the tx... */ 645 os->os_synctx = tx; 646 647 dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg); 648 649 txgoff = tx->tx_txg & TXG_MASK; 650 651 dmu_objset_sync_dnodes(os, &os->os_free_dnodes[txgoff], tx); 652 dmu_objset_sync_dnodes(os, &os->os_dirty_dnodes[txgoff], tx); 653 654 /* 655 * Free intent log blocks up to this tx. 656 */ 657 zil_sync(os->os_zil, tx); 658 659 /* 660 * Sync meta-dnode 661 */ 662 dirty_list = &os->os_dirty_dnodes[txgoff]; 663 ASSERT(list_head(dirty_list) == NULL); 664 list_insert_tail(dirty_list, os->os_meta_dnode); 665 dmu_objset_sync_dnodes(os, dirty_list, tx); 666 667 /* 668 * Sync the root block. 669 */ 670 bcopy(os->os_phys, abuf->b_data, sizeof (objset_phys_t)); 671 zb.zb_objset = os->os_dsl_dataset ? os->os_dsl_dataset->ds_object : 0; 672 zb.zb_object = 0; 673 zb.zb_level = -1; 674 zb.zb_blkid = 0; 675 err = arc_write(NULL, os->os_spa, os->os_md_checksum, 676 os->os_md_compress, tx->tx_txg, &os->os_rootbp, abuf, killer, os, 677 ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, ARC_WAIT, &zb); 678 ASSERT(err == 0); 679 VERIFY(arc_buf_remove_ref(abuf, FTAG) == 1); 680 681 dsl_dataset_set_blkptr(os->os_dsl_dataset, &os->os_rootbp, tx); 682 683 ASSERT3P(os->os_synctx, ==, tx); 684 taskq_wait(dbuf_tq); 685 os->os_synctx = NULL; 686 } 687 688 void 689 dmu_objset_stats(objset_t *os, dmu_objset_stats_t *dds) 690 { 691 if (os->os->os_dsl_dataset != NULL) { 692 dsl_dataset_stats(os->os->os_dsl_dataset, dds); 693 } else { 694 ASSERT(os->os->os_phys->os_type == DMU_OST_META); 695 bzero(dds, sizeof (*dds)); 696 } 697 dds->dds_type = os->os->os_phys->os_type; 698 } 699 700 int 701 dmu_objset_is_snapshot(objset_t *os) 702 { 703 if (os->os->os_dsl_dataset != NULL) 704 return (dsl_dataset_is_snapshot(os->os->os_dsl_dataset)); 705 else 706 return (B_FALSE); 707 } 708 709 int 710 dmu_snapshot_list_next(objset_t *os, int namelen, char *name, 711 uint64_t *idp, uint64_t *offp) 712 { 713 dsl_dataset_t *ds = os->os->os_dsl_dataset; 714 zap_cursor_t cursor; 715 zap_attribute_t attr; 716 717 if (ds->ds_phys->ds_snapnames_zapobj == 0) 718 return (ENOENT); 719 720 zap_cursor_init_serialized(&cursor, 721 ds->ds_dir->dd_pool->dp_meta_objset, 722 ds->ds_phys->ds_snapnames_zapobj, *offp); 723 724 if (zap_cursor_retrieve(&cursor, &attr) != 0) { 725 zap_cursor_fini(&cursor); 726 return (ENOENT); 727 } 728 729 if (strlen(attr.za_name) + 1 > namelen) { 730 zap_cursor_fini(&cursor); 731 return (ENAMETOOLONG); 732 } 733 734 (void) strcpy(name, attr.za_name); 735 if (idp) 736 *idp = attr.za_first_integer; 737 zap_cursor_advance(&cursor); 738 *offp = zap_cursor_serialize(&cursor); 739 zap_cursor_fini(&cursor); 740 741 return (0); 742 } 743 744 int 745 dmu_dir_list_next(objset_t *os, int namelen, char *name, 746 uint64_t *idp, uint64_t *offp) 747 { 748 dsl_dir_t *dd = os->os->os_dsl_dataset->ds_dir; 749 zap_cursor_t cursor; 750 zap_attribute_t attr; 751 752 if (dd->dd_phys->dd_child_dir_zapobj == 0) 753 return (ENOENT); 754 755 /* there is no next dir on a snapshot! */ 756 if (os->os->os_dsl_dataset->ds_object != 757 dd->dd_phys->dd_head_dataset_obj) 758 return (ENOENT); 759 760 zap_cursor_init_serialized(&cursor, 761 dd->dd_pool->dp_meta_objset, 762 dd->dd_phys->dd_child_dir_zapobj, *offp); 763 764 if (zap_cursor_retrieve(&cursor, &attr) != 0) { 765 zap_cursor_fini(&cursor); 766 return (ENOENT); 767 } 768 769 if (strlen(attr.za_name) + 1 > namelen) { 770 zap_cursor_fini(&cursor); 771 return (ENAMETOOLONG); 772 } 773 774 (void) strcpy(name, attr.za_name); 775 if (idp) 776 *idp = attr.za_first_integer; 777 zap_cursor_advance(&cursor); 778 *offp = zap_cursor_serialize(&cursor); 779 zap_cursor_fini(&cursor); 780 781 return (0); 782 } 783 784 /* 785 * Find all objsets under name, and for each, call 'func(child_name, arg)'. 786 */ 787 void 788 dmu_objset_find(char *name, void func(char *, void *), void *arg, int flags) 789 { 790 dsl_dir_t *dd; 791 objset_t *os; 792 uint64_t snapobj; 793 zap_cursor_t zc; 794 zap_attribute_t attr; 795 char *child; 796 int do_self, err; 797 798 err = dsl_dir_open(name, FTAG, &dd, NULL); 799 if (err) 800 return; 801 802 do_self = (dd->dd_phys->dd_head_dataset_obj != 0); 803 804 /* 805 * Iterate over all children. 806 */ 807 if (dd->dd_phys->dd_child_dir_zapobj != 0) { 808 for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, 809 dd->dd_phys->dd_child_dir_zapobj); 810 zap_cursor_retrieve(&zc, &attr) == 0; 811 (void) zap_cursor_advance(&zc)) { 812 ASSERT(attr.za_integer_length == sizeof (uint64_t)); 813 ASSERT(attr.za_num_integers == 1); 814 815 /* 816 * No separating '/' because parent's name ends in /. 817 */ 818 child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 819 /* XXX could probably just use name here */ 820 dsl_dir_name(dd, child); 821 (void) strcat(child, "/"); 822 (void) strcat(child, attr.za_name); 823 dmu_objset_find(child, func, arg, flags); 824 kmem_free(child, MAXPATHLEN); 825 } 826 zap_cursor_fini(&zc); 827 } 828 829 /* 830 * Iterate over all snapshots. 831 */ 832 if ((flags & DS_FIND_SNAPSHOTS) && 833 dmu_objset_open(name, DMU_OST_ANY, 834 DS_MODE_STANDARD | DS_MODE_READONLY, &os) == 0) { 835 836 snapobj = os->os->os_dsl_dataset->ds_phys->ds_snapnames_zapobj; 837 dmu_objset_close(os); 838 839 for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, snapobj); 840 zap_cursor_retrieve(&zc, &attr) == 0; 841 (void) zap_cursor_advance(&zc)) { 842 ASSERT(attr.za_integer_length == sizeof (uint64_t)); 843 ASSERT(attr.za_num_integers == 1); 844 845 child = kmem_alloc(MAXPATHLEN, KM_SLEEP); 846 /* XXX could probably just use name here */ 847 dsl_dir_name(dd, child); 848 (void) strcat(child, "@"); 849 (void) strcat(child, attr.za_name); 850 func(child, arg); 851 kmem_free(child, MAXPATHLEN); 852 } 853 zap_cursor_fini(&zc); 854 } 855 856 dsl_dir_close(dd, FTAG); 857 858 /* 859 * Apply to self if appropriate. 860 */ 861 if (do_self) 862 func(name, arg); 863 } 864