1192303Sbrueffer/*- 2176698Sbrueffer * SPDX-License-Identifier: BSD-2-Clause 3176698Sbrueffer * 4176698Sbrueffer * Copyright (c) 2022 The FreeBSD Foundation 5176698Sbrueffer * 6176698Sbrueffer * This software was developed by Mark Johnston under sponsorship from 7176698Sbrueffer * the FreeBSD Foundation. 8176698Sbrueffer * 9176698Sbrueffer * Redistribution and use in source and binary forms, with or without 10176698Sbrueffer * modification, are permitted provided that the following conditions are 11176698Sbrueffer * met: 12176698Sbrueffer * 1. Redistributions of source code must retain the above copyright 13176698Sbrueffer * notice, this list of conditions and the following disclaimer. 14176698Sbrueffer * 2. Redistributions in binary form must reproduce the above copyright 15176698Sbrueffer * notice, this list of conditions and the following disclaimer in 16176698Sbrueffer * the documentation and/or other materials provided with the distribution. 17176698Sbrueffer * 18176698Sbrueffer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19176698Sbrueffer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20176698Sbrueffer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21176698Sbrueffer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22176698Sbrueffer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23176698Sbrueffer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24176698Sbrueffer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25176698Sbrueffer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26176698Sbrueffer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27176698Sbrueffer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28176698Sbrueffer * SUCH DAMAGE. 29176698Sbrueffer */ 30176698Sbrueffer 31176698Sbrueffer#include <assert.h> 32227750Smiwi#include <stdlib.h> 33176698Sbrueffer#include <string.h> 34176698Sbrueffer 35176698Sbrueffer#include <util.h> 36176698Sbrueffer 37176698Sbrueffer#include "makefs.h" 38176698Sbrueffer#include "zfs.h" 39176698Sbrueffer 40176698Sbrueffertypedef struct zfs_dsl_dataset { 41176698Sbrueffer zfs_objset_t *os; /* referenced objset, may be null */ 42176698Sbrueffer dsl_dataset_phys_t *phys; /* on-disk representation */ 43227750Smiwi uint64_t dsid; /* DSL dataset dnode */ 44227750Smiwi 45176698Sbrueffer struct zfs_dsl_dir *dir; /* containing parent */ 46176698Sbrueffer} zfs_dsl_dataset_t; 47192141Sbrueffer 48192141Sbrueffertypedef STAILQ_HEAD(zfs_dsl_dir_list, zfs_dsl_dir) zfs_dsl_dir_list_t; 49192141Sbrueffer 50192141Sbrueffertypedef struct zfs_dsl_dir { 51192141Sbrueffer char *fullname; /* full dataset name */ 52192141Sbrueffer char *name; /* basename(fullname) */ 53192141Sbrueffer dsl_dir_phys_t *phys; /* on-disk representation */ 54176698Sbrueffer nvlist_t *propsnv; /* properties saved in propszap */ 55176698Sbrueffer 56176698Sbrueffer zfs_dsl_dataset_t *headds; /* principal dataset, may be null */ 57176698Sbrueffer 58176698Sbrueffer uint64_t dirid; /* DSL directory dnode */ 59176698Sbrueffer zfs_zap_t *propszap; /* dataset properties */ 60176698Sbrueffer zfs_zap_t *childzap; /* child directories */ 61176698Sbrueffer 62176698Sbrueffer /* DSL directory tree linkage. */ 63176698Sbrueffer struct zfs_dsl_dir *parent; 64176698Sbrueffer zfs_dsl_dir_list_t children; 65176698Sbrueffer STAILQ_ENTRY(zfs_dsl_dir) next; 66176698Sbrueffer} zfs_dsl_dir_t; 67176698Sbrueffer 68176698Sbruefferstatic zfs_dsl_dir_t *dsl_dir_alloc(zfs_opt_t *zfs, const char *name); 69176698Sbruefferstatic zfs_dsl_dataset_t *dsl_dataset_alloc(zfs_opt_t *zfs, zfs_dsl_dir_t *dir); 70176698Sbrueffer 71176698Sbruefferstatic int 72176698Sbrueffernvlist_find_string(nvlist_t *nvl, const char *key, char **retp) 73176698Sbrueffer{ 74176698Sbrueffer char *str; 75176698Sbrueffer int error, len; 76176698Sbrueffer 77176698Sbrueffer error = nvlist_find(nvl, key, DATA_TYPE_STRING, NULL, &str, &len); 78176698Sbrueffer if (error == 0) { 79176698Sbrueffer *retp = ecalloc(1, len + 1); 80176698Sbrueffer memcpy(*retp, str, len); 81176698Sbrueffer } 82176698Sbrueffer return (error); 83176698Sbrueffer} 84176698Sbrueffer 85192303Sbruefferstatic int 86176698Sbrueffernvlist_find_uint64(nvlist_t *nvl, const char *key, uint64_t *retp) 87176698Sbrueffer{ 88176698Sbrueffer 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 */ 98char * 99dsl_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 141int 142dsl_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 */ 154static void 155dsl_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 { 197 errx(1, "unknown property `%s'", key); 198 } 199} 200 201static zfs_dsl_dir_t * 202dsl_metadir_alloc(zfs_opt_t *zfs, const char *name) 203{ 204 zfs_dsl_dir_t *dir; 205 char *path; 206 207 easprintf(&path, "%s/%s", zfs->poolname, name); 208 dir = dsl_dir_alloc(zfs, path); 209 free(path); 210 return (dir); 211} 212 213static void 214dsl_origindir_init(zfs_opt_t *zfs) 215{ 216 dnode_phys_t *clones; 217 uint64_t clonesid; 218 219 zfs->origindsldir = dsl_metadir_alloc(zfs, "$ORIGIN"); 220 zfs->originds = dsl_dataset_alloc(zfs, zfs->origindsldir); 221 zfs->snapds = dsl_dataset_alloc(zfs, zfs->origindsldir); 222 223 clones = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_CLONES, &clonesid); 224 zfs->cloneszap = zap_alloc(zfs->mos, clones); 225 zfs->origindsldir->phys->dd_clones = clonesid; 226} 227 228void 229dsl_init(zfs_opt_t *zfs) 230{ 231 zfs_dsl_dir_t *dir; 232 struct dataset_desc *d; 233 const char *dspropdelim; 234 235 dspropdelim = ";"; 236 237 zfs->rootdsldir = dsl_dir_alloc(zfs, NULL); 238 239 nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression", 240 ZIO_COMPRESS_OFF); 241 242 zfs->rootds = dsl_dataset_alloc(zfs, zfs->rootdsldir); 243 zfs->rootdsldir->headds = zfs->rootds; 244 245 zfs->mosdsldir = dsl_metadir_alloc(zfs, "$MOS"); 246 zfs->freedsldir = dsl_metadir_alloc(zfs, "$FREE"); 247 dsl_origindir_init(zfs); 248 249 /* 250 * Go through the list of user-specified datasets and create DSL objects 251 * for them. 252 */ 253 STAILQ_FOREACH(d, &zfs->datasetdescs, next) { 254 char *dsname, *next, *params, *param, *nextparam; 255 256 params = d->params; 257 dsname = strsep(¶ms, dspropdelim); 258 259 if (strcmp(dsname, zfs->poolname) == 0) { 260 /* 261 * This is the root dataset; it's already created, so 262 * we're just setting options. 263 */ 264 dir = zfs->rootdsldir; 265 } else { 266 /* 267 * This dataset must be a child of the root dataset. 268 */ 269 if (strstr(dsname, zfs->poolname) != dsname || 270 (next = strchr(dsname, '/')) == NULL || 271 (size_t)(next - dsname) != strlen(zfs->poolname)) { 272 errx(1, "dataset `%s' must be a child of `%s'", 273 dsname, zfs->poolname); 274 } 275 dir = dsl_dir_alloc(zfs, dsname); 276 dir->headds = dsl_dataset_alloc(zfs, dir); 277 } 278 279 for (nextparam = param = params; nextparam != NULL;) { 280 char *key, *val; 281 282 param = strsep(&nextparam, dspropdelim); 283 284 key = val = param; 285 key = strsep(&val, "="); 286 dsl_dir_set_prop(zfs, dir, key, val); 287 } 288 } 289 290 /* 291 * Set the root dataset's mount point if the user didn't override the 292 * default. 293 */ 294 if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) { 295 nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint", 296 zfs->rootpath); 297 } 298} 299 300uint64_t 301dsl_dir_id(zfs_dsl_dir_t *dir) 302{ 303 return (dir->dirid); 304} 305 306uint64_t 307dsl_dir_dataset_id(zfs_dsl_dir_t *dir) 308{ 309 return (dir->headds->dsid); 310} 311 312static void 313dsl_dir_foreach_post(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, 314 void (*cb)(zfs_opt_t *, zfs_dsl_dir_t *, void *), void *arg) 315{ 316 zfs_dsl_dir_t *cdsldir; 317 318 STAILQ_FOREACH(cdsldir, &dsldir->children, next) { 319 dsl_dir_foreach_post(zfs, cdsldir, cb, arg); 320 } 321 cb(zfs, dsldir, arg); 322} 323 324/* 325 * Used when the caller doesn't care about the order one way or another. 326 */ 327void 328dsl_dir_foreach(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, 329 void (*cb)(zfs_opt_t *, zfs_dsl_dir_t *, void *), void *arg) 330{ 331 dsl_dir_foreach_post(zfs, dsldir, cb, arg); 332} 333 334const char * 335dsl_dir_fullname(const zfs_dsl_dir_t *dir) 336{ 337 return (dir->fullname); 338} 339 340/* 341 * Create a DSL directory, which is effectively an entry in the ZFS namespace. 342 * We always create a root DSL directory, whose name is the pool's name, and 343 * several metadata directories. 344 * 345 * Each directory has two ZAP objects, one pointing to child directories, and 346 * one for properties (which are inherited by children unless overridden). 347 * Directories typically reference a DSL dataset, the "head dataset", which 348 * points to an object set. 349 */ 350static zfs_dsl_dir_t * 351dsl_dir_alloc(zfs_opt_t *zfs, const char *name) 352{ 353 zfs_dsl_dir_list_t l, *lp; 354 zfs_dsl_dir_t *dir, *parent; 355 dnode_phys_t *dnode; 356 char *dirname, *nextdir, *origname; 357 uint64_t childid, propsid; 358 359 dir = ecalloc(1, sizeof(*dir)); 360 361 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DSL_DIR, 362 DMU_OT_DSL_DIR, sizeof(dsl_dir_phys_t), &dir->dirid); 363 dir->phys = (dsl_dir_phys_t *)DN_BONUS(dnode); 364 365 dnode = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_PROPS, &propsid); 366 dir->propszap = zap_alloc(zfs->mos, dnode); 367 368 dnode = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DIR_CHILD_MAP, 369 &childid); 370 dir->childzap = zap_alloc(zfs->mos, dnode); 371 372 dir->propsnv = nvlist_create(NV_UNIQUE_NAME); 373 STAILQ_INIT(&dir->children); 374 375 dir->phys->dd_child_dir_zapobj = childid; 376 dir->phys->dd_props_zapobj = propsid; 377 378 if (name == NULL) { 379 /* 380 * This is the root DSL directory. 381 */ 382 dir->name = estrdup(zfs->poolname); 383 dir->fullname = estrdup(zfs->poolname); 384 dir->parent = NULL; 385 dir->phys->dd_parent_obj = 0; 386 387 assert(zfs->rootdsldir == NULL); 388 zfs->rootdsldir = dir; 389 return (dir); 390 } 391 392 /* 393 * Insert the new directory into the hierarchy. Currently this must be 394 * done in order, e.g., when creating pool/a/b, pool/a must already 395 * exist. 396 */ 397 STAILQ_INIT(&l); 398 STAILQ_INSERT_HEAD(&l, zfs->rootdsldir, next); 399 origname = dirname = nextdir = estrdup(name); 400 for (lp = &l;; lp = &parent->children) { 401 dirname = strsep(&nextdir, "/"); 402 if (nextdir == NULL) 403 break; 404 405 STAILQ_FOREACH(parent, lp, next) { 406 if (strcmp(parent->name, dirname) == 0) 407 break; 408 } 409 if (parent == NULL) { 410 errx(1, "no parent at `%s' for filesystem `%s'", 411 dirname, name); 412 } 413 } 414 415 dir->fullname = estrdup(name); 416 dir->name = estrdup(dirname); 417 free(origname); 418 STAILQ_INSERT_TAIL(lp, dir, next); 419 zap_add_uint64(parent->childzap, dir->name, dir->dirid); 420 421 dir->parent = parent; 422 dir->phys->dd_parent_obj = parent->dirid; 423 return (dir); 424} 425 426static void 427dsl_dir_size_add(zfs_dsl_dir_t *dir, uint64_t bytes) 428{ 429 dir->phys->dd_used_bytes += bytes; 430 dir->phys->dd_compressed_bytes += bytes; 431 dir->phys->dd_uncompressed_bytes += bytes; 432} 433 434/* 435 * See dsl_dir_root_finalize(). 436 */ 437void 438dsl_dir_root_finalize(zfs_opt_t *zfs, uint64_t bytes) 439{ 440 dsl_dir_size_add(zfs->mosdsldir, bytes); 441 zfs->mosdsldir->phys->dd_used_breakdown[DD_USED_HEAD] += bytes; 442 443 dsl_dir_size_add(zfs->rootdsldir, bytes); 444 zfs->rootdsldir->phys->dd_used_breakdown[DD_USED_CHILD] += bytes; 445} 446 447/* 448 * Convert dataset properties into entries in the DSL directory's properties 449 * ZAP. 450 */ 451static void 452dsl_dir_finalize_props(zfs_dsl_dir_t *dir) 453{ 454 for (nvp_header_t *nvh = NULL; 455 (nvh = nvlist_next_nvpair(dir->propsnv, nvh)) != NULL;) { 456 nv_string_t *nvname; 457 nv_pair_data_t *nvdata; 458 char *name; 459 460 nvname = (nv_string_t *)(nvh + 1); 461 nvdata = (nv_pair_data_t *)(&nvname->nv_data[0] + 462 NV_ALIGN4(nvname->nv_size)); 463 464 name = nvstring_get(nvname); 465 switch (nvdata->nv_type) { 466 case DATA_TYPE_UINT64: { 467 uint64_t val; 468 469 memcpy(&val, &nvdata->nv_data[0], sizeof(uint64_t)); 470 zap_add_uint64(dir->propszap, name, val); 471 break; 472 } 473 case DATA_TYPE_STRING: { 474 nv_string_t *nvstr; 475 char *val; 476 477 nvstr = (nv_string_t *)&nvdata->nv_data[0]; 478 val = nvstring_get(nvstr); 479 zap_add_string(dir->propszap, name, val); 480 free(val); 481 break; 482 } 483 default: 484 assert(0); 485 } 486 free(name); 487 } 488} 489 490static void 491dsl_dir_finalize(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, void *arg __unused) 492{ 493 zfs_dsl_dir_t *cdir; 494 dnode_phys_t *snapnames; 495 zfs_dsl_dataset_t *headds; 496 zfs_objset_t *os; 497 uint64_t bytes, childbytes, snapnamesid; 498 499 dsl_dir_finalize_props(dir); 500 zap_write(zfs, dir->propszap); 501 zap_write(zfs, dir->childzap); 502 503 headds = dir->headds; 504 if (headds == NULL) 505 return; 506 os = headds->os; 507 if (os == NULL) 508 return; 509 510 snapnames = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DS_SNAP_MAP, 511 &snapnamesid); 512 zap_write(zfs, zap_alloc(zfs->mos, snapnames)); 513 514 dir->phys->dd_head_dataset_obj = headds->dsid; 515 dir->phys->dd_clone_parent_obj = zfs->snapds->dsid; 516 headds->phys->ds_prev_snap_obj = zfs->snapds->dsid; 517 headds->phys->ds_snapnames_zapobj = snapnamesid; 518 objset_root_blkptr_copy(os, &headds->phys->ds_bp); 519 520 zfs->snapds->phys->ds_num_children++; 521 zap_add_uint64_self(zfs->cloneszap, headds->dsid); 522 523 bytes = objset_space(os); 524 headds->phys->ds_used_bytes = bytes; 525 headds->phys->ds_uncompressed_bytes = bytes; 526 headds->phys->ds_compressed_bytes = bytes; 527 528 childbytes = 0; 529 STAILQ_FOREACH(cdir, &dir->children, next) { 530 /* 531 * The root directory needs a special case: the amount of 532 * space used for the MOS isn't known until everything else is 533 * finalized, so it can't be accounted in the MOS directory's 534 * parent until then, at which point dsl_dir_root_finalize() is 535 * called. 536 */ 537 if (dir == zfs->rootdsldir && cdir == zfs->mosdsldir) 538 continue; 539 childbytes += cdir->phys->dd_used_bytes; 540 } 541 dsl_dir_size_add(dir, bytes + childbytes); 542 543 dir->phys->dd_flags |= DD_FLAG_USED_BREAKDOWN; 544 dir->phys->dd_used_breakdown[DD_USED_HEAD] = bytes; 545 dir->phys->dd_used_breakdown[DD_USED_CHILD] = childbytes; 546} 547 548void 549dsl_write(zfs_opt_t *zfs) 550{ 551 zfs_zap_t *snapnameszap; 552 dnode_phys_t *snapnames; 553 uint64_t snapmapid; 554 555 /* 556 * Perform accounting, starting from the leaves of the DSL directory 557 * tree. Accounting for $MOS is done later, once we've finished 558 * allocating space. 559 */ 560 dsl_dir_foreach_post(zfs, zfs->rootdsldir, dsl_dir_finalize, NULL); 561 562 snapnames = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DS_SNAP_MAP, 563 &snapmapid); 564 snapnameszap = zap_alloc(zfs->mos, snapnames); 565 zap_add_uint64(snapnameszap, "$ORIGIN", zfs->snapds->dsid); 566 zap_write(zfs, snapnameszap); 567 568 zfs->origindsldir->phys->dd_head_dataset_obj = zfs->originds->dsid; 569 zfs->originds->phys->ds_prev_snap_obj = zfs->snapds->dsid; 570 zfs->originds->phys->ds_snapnames_zapobj = snapmapid; 571 572 zfs->snapds->phys->ds_next_snap_obj = zfs->originds->dsid; 573 assert(zfs->snapds->phys->ds_num_children > 0); 574 zfs->snapds->phys->ds_num_children++; 575 576 zap_write(zfs, zfs->cloneszap); 577 578 /* XXX-MJ dirs and datasets are leaked */ 579} 580 581void 582dsl_dir_dataset_write(zfs_opt_t *zfs, zfs_objset_t *os, zfs_dsl_dir_t *dir) 583{ 584 dir->headds->os = os; 585 objset_write(zfs, os); 586} 587 588bool 589dsl_dir_has_dataset(zfs_dsl_dir_t *dir) 590{ 591 return (dir->headds != NULL); 592} 593 594bool 595dsl_dir_dataset_has_objset(zfs_dsl_dir_t *dir) 596{ 597 return (dsl_dir_has_dataset(dir) && dir->headds->os != NULL); 598} 599 600static zfs_dsl_dataset_t * 601dsl_dataset_alloc(zfs_opt_t *zfs, zfs_dsl_dir_t *dir) 602{ 603 zfs_dsl_dataset_t *ds; 604 dnode_phys_t *dnode; 605 uint64_t deadlistid; 606 607 ds = ecalloc(1, sizeof(*ds)); 608 609 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DSL_DATASET, 610 DMU_OT_DSL_DATASET, sizeof(dsl_dataset_phys_t), &ds->dsid); 611 ds->phys = (dsl_dataset_phys_t *)DN_BONUS(dnode); 612 613 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DEADLIST, 614 DMU_OT_DEADLIST_HDR, sizeof(dsl_deadlist_phys_t), &deadlistid); 615 zap_write(zfs, zap_alloc(zfs->mos, dnode)); 616 617 ds->phys->ds_dir_obj = dir->dirid; 618 ds->phys->ds_deadlist_obj = deadlistid; 619 ds->phys->ds_creation_txg = TXG - 1; 620 if (ds != zfs->snapds) 621 ds->phys->ds_prev_snap_txg = TXG - 1; 622 ds->phys->ds_guid = randomguid(); 623 ds->dir = dir; 624 625 return (ds); 626} 627