1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 The FreeBSD Foundation 5 * 6 * This software was developed by Mark Johnston under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are 11 * met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include <util.h> 36 37 #include "makefs.h" 38 #include "zfs.h" 39 40 typedef struct zfs_dsl_dataset { 41 zfs_objset_t *os; /* referenced objset, may be null */ 42 dsl_dataset_phys_t *phys; /* on-disk representation */ 43 uint64_t dsid; /* DSL dataset dnode */ 44 45 struct zfs_dsl_dir *dir; /* containing parent */ 46 } zfs_dsl_dataset_t; 47 48 typedef STAILQ_HEAD(zfs_dsl_dir_list, zfs_dsl_dir) zfs_dsl_dir_list_t; 49 50 typedef struct zfs_dsl_dir { 51 char *fullname; /* full dataset name */ 52 char *name; /* basename(fullname) */ 53 dsl_dir_phys_t *phys; /* on-disk representation */ 54 nvlist_t *propsnv; /* properties saved in propszap */ 55 56 zfs_dsl_dataset_t *headds; /* principal dataset, may be null */ 57 58 uint64_t dirid; /* DSL directory dnode */ 59 zfs_zap_t *propszap; /* dataset properties */ 60 zfs_zap_t *childzap; /* child directories */ 61 62 /* DSL directory tree linkage. */ 63 struct zfs_dsl_dir *parent; 64 zfs_dsl_dir_list_t children; 65 STAILQ_ENTRY(zfs_dsl_dir) next; 66 } zfs_dsl_dir_t; 67 68 static zfs_dsl_dir_t *dsl_dir_alloc(zfs_opt_t *zfs, const char *name); 69 static zfs_dsl_dataset_t *dsl_dataset_alloc(zfs_opt_t *zfs, zfs_dsl_dir_t *dir); 70 71 static int 72 nvlist_find_string(nvlist_t *nvl, const char *key, char **retp) 73 { 74 char *str; 75 int error, len; 76 77 error = nvlist_find(nvl, key, DATA_TYPE_STRING, NULL, &str, &len); 78 if (error == 0) { 79 *retp = ecalloc(1, len + 1); 80 memcpy(*retp, str, len); 81 } 82 return (error); 83 } 84 85 static int 86 nvlist_find_uint64(nvlist_t *nvl, const char *key, uint64_t *retp) 87 { 88 return (nvlist_find(nvl, key, DATA_TYPE_UINT64, NULL, retp, NULL)); 89 } 90 91 /* 92 * Return an allocated string containing the head dataset's mountpoint, 93 * including the root path prefix. 94 * 95 * If the dataset has a mountpoint property, it is returned. Otherwise we have 96 * to follow ZFS' inheritance rules. 97 */ 98 char * 99 dsl_dir_get_mountpoint(zfs_opt_t *zfs, zfs_dsl_dir_t *dir) 100 { 101 zfs_dsl_dir_t *pdir; 102 char *mountpoint; 103 104 if (nvlist_find_string(dir->propsnv, "mountpoint", &mountpoint) == 0) { 105 if (strcmp(mountpoint, "none") == 0) 106 return (NULL); 107 } else { 108 /* 109 * If we don't have a mountpoint, it's inherited from one of our 110 * ancestors. Walk up the hierarchy until we find it, building 111 * up our mountpoint along the way. The mountpoint property is 112 * always set for the root dataset. 113 */ 114 for (pdir = dir->parent, mountpoint = estrdup(dir->name);; 115 pdir = pdir->parent) { 116 char *origmountpoint, *tmp; 117 118 origmountpoint = mountpoint; 119 120 if (nvlist_find_string(pdir->propsnv, "mountpoint", 121 &tmp) == 0) { 122 easprintf(&mountpoint, "%s%s%s", tmp, 123 tmp[strlen(tmp) - 1] == '/' ? "" : "/", 124 origmountpoint); 125 free(tmp); 126 free(origmountpoint); 127 break; 128 } 129 130 easprintf(&mountpoint, "%s/%s", pdir->name, 131 origmountpoint); 132 free(origmountpoint); 133 } 134 } 135 assert(mountpoint[0] == '/'); 136 assert(strstr(mountpoint, zfs->rootpath) == mountpoint); 137 138 return (mountpoint); 139 } 140 141 int 142 dsl_dir_get_canmount(zfs_dsl_dir_t *dir, uint64_t *canmountp) 143 { 144 return (nvlist_find_uint64(dir->propsnv, "canmount", canmountp)); 145 } 146 147 /* 148 * Handle dataset properties that we know about; stash them into an nvlist to be 149 * written later to the properties ZAP object. 150 * 151 * If the set of properties we handle grows too much, we should probably explore 152 * using libzfs to manage them. 153 */ 154 static void 155 dsl_dir_set_prop(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, const char *key, 156 const char *val) 157 { 158 nvlist_t *nvl; 159 160 nvl = dir->propsnv; 161 if (val == NULL || val[0] == '\0') 162 errx(1, "missing value for property `%s'", key); 163 if (nvpair_find(nvl, key) != NULL) 164 errx(1, "property `%s' already set", key); 165 166 if (strcmp(key, "mountpoint") == 0) { 167 if (strcmp(val, "none") != 0) { 168 if (val[0] != '/') 169 errx(1, "mountpoint `%s' is not absolute", val); 170 if (strcmp(val, zfs->rootpath) != 0 && 171 strcmp(zfs->rootpath, "/") != 0 && 172 (strstr(val, zfs->rootpath) != val || 173 val[strlen(zfs->rootpath)] != '/')) { 174 errx(1, "mountpoint `%s' is not prefixed by " 175 "the root path `%s'", val, zfs->rootpath); 176 } 177 } 178 nvlist_add_string(nvl, key, val); 179 } else if (strcmp(key, "atime") == 0 || strcmp(key, "exec") == 0 || 180 strcmp(key, "setuid") == 0) { 181 if (strcmp(val, "on") == 0) 182 nvlist_add_uint64(nvl, key, 1); 183 else if (strcmp(val, "off") == 0) 184 nvlist_add_uint64(nvl, key, 0); 185 else 186 errx(1, "invalid value `%s' for %s", val, key); 187 } else if (strcmp(key, "canmount") == 0) { 188 if (strcmp(val, "noauto") == 0) 189 nvlist_add_uint64(nvl, key, 2); 190 else if (strcmp(val, "on") == 0) 191 nvlist_add_uint64(nvl, key, 1); 192 else if (strcmp(val, "off") == 0) 193 nvlist_add_uint64(nvl, key, 0); 194 else 195 errx(1, "invalid value `%s' for %s", val, key); 196 } else if (strcmp(key, "compression") == 0) { 197 size_t i; 198 199 const struct zfs_compression_algorithm { 200 const char *name; 201 enum zio_compress alg; 202 } compression_algorithms[] = { 203 { "off", ZIO_COMPRESS_OFF }, 204 { "on", ZIO_COMPRESS_ON }, 205 { "lzjb", ZIO_COMPRESS_LZJB }, 206 { "gzip", ZIO_COMPRESS_GZIP_6 }, 207 { "gzip-1", ZIO_COMPRESS_GZIP_1 }, 208 { "gzip-2", ZIO_COMPRESS_GZIP_2 }, 209 { "gzip-3", ZIO_COMPRESS_GZIP_3 }, 210 { "gzip-4", ZIO_COMPRESS_GZIP_4 }, 211 { "gzip-5", ZIO_COMPRESS_GZIP_5 }, 212 { "gzip-6", ZIO_COMPRESS_GZIP_6 }, 213 { "gzip-7", ZIO_COMPRESS_GZIP_7 }, 214 { "gzip-8", ZIO_COMPRESS_GZIP_8 }, 215 { "gzip-9", ZIO_COMPRESS_GZIP_9 }, 216 { "zle", ZIO_COMPRESS_ZLE }, 217 { "lz4", ZIO_COMPRESS_LZ4 }, 218 { "zstd", ZIO_COMPRESS_ZSTD }, 219 }; 220 for (i = 0; i < nitems(compression_algorithms); i++) { 221 if (strcmp(val, compression_algorithms[i].name) == 0) { 222 nvlist_add_uint64(nvl, key, 223 compression_algorithms[i].alg); 224 break; 225 } 226 } 227 if (i == nitems(compression_algorithms)) 228 errx(1, "invalid compression algorithm `%s'", val); 229 } else { 230 errx(1, "unknown property `%s'", key); 231 } 232 } 233 234 static zfs_dsl_dir_t * 235 dsl_metadir_alloc(zfs_opt_t *zfs, const char *name) 236 { 237 zfs_dsl_dir_t *dir; 238 char *path; 239 240 easprintf(&path, "%s/%s", zfs->poolname, name); 241 dir = dsl_dir_alloc(zfs, path); 242 free(path); 243 return (dir); 244 } 245 246 static void 247 dsl_origindir_init(zfs_opt_t *zfs) 248 { 249 dnode_phys_t *clones; 250 uint64_t clonesid; 251 252 zfs->origindsldir = dsl_metadir_alloc(zfs, "$ORIGIN"); 253 zfs->originds = dsl_dataset_alloc(zfs, zfs->origindsldir); 254 zfs->snapds = dsl_dataset_alloc(zfs, zfs->origindsldir); 255 256 clones = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_CLONES, &clonesid); 257 zfs->cloneszap = zap_alloc(zfs->mos, clones); 258 zfs->origindsldir->phys->dd_clones = clonesid; 259 } 260 261 void 262 dsl_init(zfs_opt_t *zfs) 263 { 264 zfs_dsl_dir_t *dir; 265 struct dataset_desc *d; 266 const char *dspropdelim; 267 268 dspropdelim = ";"; 269 270 zfs->rootdsldir = dsl_dir_alloc(zfs, NULL); 271 272 zfs->rootds = dsl_dataset_alloc(zfs, zfs->rootdsldir); 273 zfs->rootdsldir->headds = zfs->rootds; 274 275 zfs->mosdsldir = dsl_metadir_alloc(zfs, "$MOS"); 276 zfs->freedsldir = dsl_metadir_alloc(zfs, "$FREE"); 277 dsl_origindir_init(zfs); 278 279 /* 280 * Go through the list of user-specified datasets and create DSL objects 281 * for them. 282 */ 283 STAILQ_FOREACH(d, &zfs->datasetdescs, next) { 284 char *dsname, *next, *params, *param, *nextparam; 285 286 params = d->params; 287 dsname = strsep(¶ms, dspropdelim); 288 289 if (strcmp(dsname, zfs->poolname) == 0) { 290 /* 291 * This is the root dataset; it's already created, so 292 * we're just setting options. 293 */ 294 dir = zfs->rootdsldir; 295 } else { 296 /* 297 * This dataset must be a child of the root dataset. 298 */ 299 if (strstr(dsname, zfs->poolname) != dsname || 300 (next = strchr(dsname, '/')) == NULL || 301 (size_t)(next - dsname) != strlen(zfs->poolname)) { 302 errx(1, "dataset `%s' must be a child of `%s'", 303 dsname, zfs->poolname); 304 } 305 dir = dsl_dir_alloc(zfs, dsname); 306 dir->headds = dsl_dataset_alloc(zfs, dir); 307 } 308 309 for (nextparam = param = params; nextparam != NULL;) { 310 char *key, *val; 311 312 param = strsep(&nextparam, dspropdelim); 313 314 key = val = param; 315 key = strsep(&val, "="); 316 dsl_dir_set_prop(zfs, dir, key, val); 317 } 318 } 319 320 /* 321 * Set the root dataset's mount point and compression strategy if the 322 * user didn't override the defaults. 323 */ 324 if (nvpair_find(zfs->rootdsldir->propsnv, "compression") == NULL) { 325 nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression", 326 ZIO_COMPRESS_OFF); 327 } 328 if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) { 329 nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint", 330 zfs->rootpath); 331 } 332 } 333 334 uint64_t 335 dsl_dir_id(zfs_dsl_dir_t *dir) 336 { 337 return (dir->dirid); 338 } 339 340 uint64_t 341 dsl_dir_dataset_id(zfs_dsl_dir_t *dir) 342 { 343 return (dir->headds->dsid); 344 } 345 346 static void 347 dsl_dir_foreach_post(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, 348 void (*cb)(zfs_opt_t *, zfs_dsl_dir_t *, void *), void *arg) 349 { 350 zfs_dsl_dir_t *cdsldir; 351 352 STAILQ_FOREACH(cdsldir, &dsldir->children, next) { 353 dsl_dir_foreach_post(zfs, cdsldir, cb, arg); 354 } 355 cb(zfs, dsldir, arg); 356 } 357 358 /* 359 * Used when the caller doesn't care about the order one way or another. 360 */ 361 void 362 dsl_dir_foreach(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, 363 void (*cb)(zfs_opt_t *, zfs_dsl_dir_t *, void *), void *arg) 364 { 365 dsl_dir_foreach_post(zfs, dsldir, cb, arg); 366 } 367 368 const char * 369 dsl_dir_fullname(const zfs_dsl_dir_t *dir) 370 { 371 return (dir->fullname); 372 } 373 374 /* 375 * Create a DSL directory, which is effectively an entry in the ZFS namespace. 376 * We always create a root DSL directory, whose name is the pool's name, and 377 * several metadata directories. 378 * 379 * Each directory has two ZAP objects, one pointing to child directories, and 380 * one for properties (which are inherited by children unless overridden). 381 * Directories typically reference a DSL dataset, the "head dataset", which 382 * points to an object set. 383 */ 384 static zfs_dsl_dir_t * 385 dsl_dir_alloc(zfs_opt_t *zfs, const char *name) 386 { 387 zfs_dsl_dir_list_t l, *lp; 388 zfs_dsl_dir_t *dir, *parent; 389 dnode_phys_t *dnode; 390 char *dirname, *nextdir, *origname; 391 uint64_t childid, propsid; 392 393 dir = ecalloc(1, sizeof(*dir)); 394 395 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DSL_DIR, 396 DMU_OT_DSL_DIR, sizeof(dsl_dir_phys_t), &dir->dirid); 397 dir->phys = (dsl_dir_phys_t *)DN_BONUS(dnode); 398 399 dnode = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_PROPS, &propsid); 400 dir->propszap = zap_alloc(zfs->mos, dnode); 401 402 dnode = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DIR_CHILD_MAP, 403 &childid); 404 dir->childzap = zap_alloc(zfs->mos, dnode); 405 406 dir->propsnv = nvlist_create(NV_UNIQUE_NAME); 407 STAILQ_INIT(&dir->children); 408 409 dir->phys->dd_child_dir_zapobj = childid; 410 dir->phys->dd_props_zapobj = propsid; 411 412 if (name == NULL) { 413 /* 414 * This is the root DSL directory. 415 */ 416 dir->name = estrdup(zfs->poolname); 417 dir->fullname = estrdup(zfs->poolname); 418 dir->parent = NULL; 419 dir->phys->dd_parent_obj = 0; 420 421 assert(zfs->rootdsldir == NULL); 422 zfs->rootdsldir = dir; 423 return (dir); 424 } 425 426 /* 427 * Insert the new directory into the hierarchy. Currently this must be 428 * done in order, e.g., when creating pool/a/b, pool/a must already 429 * exist. 430 */ 431 STAILQ_INIT(&l); 432 STAILQ_INSERT_HEAD(&l, zfs->rootdsldir, next); 433 origname = dirname = nextdir = estrdup(name); 434 for (lp = &l;; lp = &parent->children) { 435 dirname = strsep(&nextdir, "/"); 436 if (nextdir == NULL) 437 break; 438 439 STAILQ_FOREACH(parent, lp, next) { 440 if (strcmp(parent->name, dirname) == 0) 441 break; 442 } 443 if (parent == NULL) { 444 errx(1, "no parent at `%s' for filesystem `%s'", 445 dirname, name); 446 } 447 } 448 449 dir->fullname = estrdup(name); 450 dir->name = estrdup(dirname); 451 free(origname); 452 STAILQ_INSERT_TAIL(lp, dir, next); 453 zap_add_uint64(parent->childzap, dir->name, dir->dirid); 454 455 dir->parent = parent; 456 dir->phys->dd_parent_obj = parent->dirid; 457 return (dir); 458 } 459 460 static void 461 dsl_dir_size_add(zfs_dsl_dir_t *dir, uint64_t bytes) 462 { 463 dir->phys->dd_used_bytes += bytes; 464 dir->phys->dd_compressed_bytes += bytes; 465 dir->phys->dd_uncompressed_bytes += bytes; 466 } 467 468 /* 469 * See dsl_dir_root_finalize(). 470 */ 471 void 472 dsl_dir_root_finalize(zfs_opt_t *zfs, uint64_t bytes) 473 { 474 dsl_dir_size_add(zfs->mosdsldir, bytes); 475 zfs->mosdsldir->phys->dd_used_breakdown[DD_USED_HEAD] += bytes; 476 477 dsl_dir_size_add(zfs->rootdsldir, bytes); 478 zfs->rootdsldir->phys->dd_used_breakdown[DD_USED_CHILD] += bytes; 479 } 480 481 /* 482 * Convert dataset properties into entries in the DSL directory's properties 483 * ZAP. 484 */ 485 static void 486 dsl_dir_finalize_props(zfs_dsl_dir_t *dir) 487 { 488 for (nvp_header_t *nvh = NULL; 489 (nvh = nvlist_next_nvpair(dir->propsnv, nvh)) != NULL;) { 490 nv_string_t *nvname; 491 nv_pair_data_t *nvdata; 492 char *name; 493 494 nvname = (nv_string_t *)(nvh + 1); 495 nvdata = (nv_pair_data_t *)(&nvname->nv_data[0] + 496 NV_ALIGN4(nvname->nv_size)); 497 498 name = nvstring_get(nvname); 499 switch (nvdata->nv_type) { 500 case DATA_TYPE_UINT64: { 501 uint64_t val; 502 503 memcpy(&val, &nvdata->nv_data[0], sizeof(uint64_t)); 504 zap_add_uint64(dir->propszap, name, val); 505 break; 506 } 507 case DATA_TYPE_STRING: { 508 nv_string_t *nvstr; 509 char *val; 510 511 nvstr = (nv_string_t *)&nvdata->nv_data[0]; 512 val = nvstring_get(nvstr); 513 zap_add_string(dir->propszap, name, val); 514 free(val); 515 break; 516 } 517 default: 518 assert(0); 519 } 520 free(name); 521 } 522 } 523 524 static void 525 dsl_dir_finalize(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, void *arg __unused) 526 { 527 zfs_dsl_dir_t *cdir; 528 dnode_phys_t *snapnames; 529 zfs_dsl_dataset_t *headds; 530 zfs_objset_t *os; 531 uint64_t bytes, childbytes, snapnamesid; 532 533 dsl_dir_finalize_props(dir); 534 zap_write(zfs, dir->propszap); 535 zap_write(zfs, dir->childzap); 536 537 headds = dir->headds; 538 if (headds == NULL) 539 return; 540 os = headds->os; 541 if (os == NULL) 542 return; 543 544 snapnames = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DS_SNAP_MAP, 545 &snapnamesid); 546 zap_write(zfs, zap_alloc(zfs->mos, snapnames)); 547 548 dir->phys->dd_head_dataset_obj = headds->dsid; 549 dir->phys->dd_clone_parent_obj = zfs->snapds->dsid; 550 headds->phys->ds_prev_snap_obj = zfs->snapds->dsid; 551 headds->phys->ds_snapnames_zapobj = snapnamesid; 552 objset_root_blkptr_copy(os, &headds->phys->ds_bp); 553 554 zfs->snapds->phys->ds_num_children++; 555 zap_add_uint64_self(zfs->cloneszap, headds->dsid); 556 557 bytes = objset_space(os); 558 headds->phys->ds_used_bytes = bytes; 559 headds->phys->ds_uncompressed_bytes = bytes; 560 headds->phys->ds_compressed_bytes = bytes; 561 562 childbytes = 0; 563 STAILQ_FOREACH(cdir, &dir->children, next) { 564 /* 565 * The root directory needs a special case: the amount of 566 * space used for the MOS isn't known until everything else is 567 * finalized, so it can't be accounted in the MOS directory's 568 * parent until then, at which point dsl_dir_root_finalize() is 569 * called. 570 */ 571 if (dir == zfs->rootdsldir && cdir == zfs->mosdsldir) 572 continue; 573 childbytes += cdir->phys->dd_used_bytes; 574 } 575 dsl_dir_size_add(dir, bytes + childbytes); 576 577 dir->phys->dd_flags |= DD_FLAG_USED_BREAKDOWN; 578 dir->phys->dd_used_breakdown[DD_USED_HEAD] = bytes; 579 dir->phys->dd_used_breakdown[DD_USED_CHILD] = childbytes; 580 } 581 582 void 583 dsl_write(zfs_opt_t *zfs) 584 { 585 zfs_zap_t *snapnameszap; 586 dnode_phys_t *snapnames; 587 uint64_t snapmapid; 588 589 /* 590 * Perform accounting, starting from the leaves of the DSL directory 591 * tree. Accounting for $MOS is done later, once we've finished 592 * allocating space. 593 */ 594 dsl_dir_foreach_post(zfs, zfs->rootdsldir, dsl_dir_finalize, NULL); 595 596 snapnames = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DS_SNAP_MAP, 597 &snapmapid); 598 snapnameszap = zap_alloc(zfs->mos, snapnames); 599 zap_add_uint64(snapnameszap, "$ORIGIN", zfs->snapds->dsid); 600 zap_write(zfs, snapnameszap); 601 602 zfs->origindsldir->phys->dd_head_dataset_obj = zfs->originds->dsid; 603 zfs->originds->phys->ds_prev_snap_obj = zfs->snapds->dsid; 604 zfs->originds->phys->ds_snapnames_zapobj = snapmapid; 605 606 zfs->snapds->phys->ds_next_snap_obj = zfs->originds->dsid; 607 assert(zfs->snapds->phys->ds_num_children > 0); 608 zfs->snapds->phys->ds_num_children++; 609 610 zap_write(zfs, zfs->cloneszap); 611 612 /* XXX-MJ dirs and datasets are leaked */ 613 } 614 615 void 616 dsl_dir_dataset_write(zfs_opt_t *zfs, zfs_objset_t *os, zfs_dsl_dir_t *dir) 617 { 618 dir->headds->os = os; 619 objset_write(zfs, os); 620 } 621 622 bool 623 dsl_dir_has_dataset(zfs_dsl_dir_t *dir) 624 { 625 return (dir->headds != NULL); 626 } 627 628 bool 629 dsl_dir_dataset_has_objset(zfs_dsl_dir_t *dir) 630 { 631 return (dsl_dir_has_dataset(dir) && dir->headds->os != NULL); 632 } 633 634 static zfs_dsl_dataset_t * 635 dsl_dataset_alloc(zfs_opt_t *zfs, zfs_dsl_dir_t *dir) 636 { 637 zfs_dsl_dataset_t *ds; 638 dnode_phys_t *dnode; 639 uint64_t deadlistid; 640 641 ds = ecalloc(1, sizeof(*ds)); 642 643 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DSL_DATASET, 644 DMU_OT_DSL_DATASET, sizeof(dsl_dataset_phys_t), &ds->dsid); 645 ds->phys = (dsl_dataset_phys_t *)DN_BONUS(dnode); 646 647 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DEADLIST, 648 DMU_OT_DEADLIST_HDR, sizeof(dsl_deadlist_phys_t), &deadlistid); 649 zap_write(zfs, zap_alloc(zfs->mos, dnode)); 650 651 ds->phys->ds_dir_obj = dir->dirid; 652 ds->phys->ds_deadlist_obj = deadlistid; 653 ds->phys->ds_creation_txg = TXG - 1; 654 if (ds != zfs->snapds) 655 ds->phys->ds_prev_snap_txg = TXG - 1; 656 ds->phys->ds_guid = randomguid(); 657 ds->dir = dir; 658 659 return (ds); 660 } 661