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
nvlist_find_string(nvlist_t * nvl,const char * key,char ** retp)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
nvlist_find_uint64(nvlist_t * nvl,const char * key,uint64_t * retp)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 *
dsl_dir_get_mountpoint(zfs_opt_t * zfs,zfs_dsl_dir_t * dir)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
dsl_dir_get_canmount(zfs_dsl_dir_t * dir,uint64_t * canmountp)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
dsl_dir_set_prop(zfs_opt_t * zfs,zfs_dsl_dir_t * dir,const char * key,const char * val)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 {
197 errx(1, "unknown property `%s'", key);
198 }
199 }
200
201 static zfs_dsl_dir_t *
dsl_metadir_alloc(zfs_opt_t * zfs,const char * name)202 dsl_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
213 static void
dsl_origindir_init(zfs_opt_t * zfs)214 dsl_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
228 void
dsl_init(zfs_opt_t * zfs)229 dsl_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
300 uint64_t
dsl_dir_id(zfs_dsl_dir_t * dir)301 dsl_dir_id(zfs_dsl_dir_t *dir)
302 {
303 return (dir->dirid);
304 }
305
306 uint64_t
dsl_dir_dataset_id(zfs_dsl_dir_t * dir)307 dsl_dir_dataset_id(zfs_dsl_dir_t *dir)
308 {
309 return (dir->headds->dsid);
310 }
311
312 static void
dsl_dir_foreach_post(zfs_opt_t * zfs,zfs_dsl_dir_t * dsldir,void (* cb)(zfs_opt_t *,zfs_dsl_dir_t *,void *),void * arg)313 dsl_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 */
327 void
dsl_dir_foreach(zfs_opt_t * zfs,zfs_dsl_dir_t * dsldir,void (* cb)(zfs_opt_t *,zfs_dsl_dir_t *,void *),void * arg)328 dsl_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
334 const char *
dsl_dir_fullname(const zfs_dsl_dir_t * dir)335 dsl_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 */
350 static zfs_dsl_dir_t *
dsl_dir_alloc(zfs_opt_t * zfs,const char * name)351 dsl_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
426 static void
dsl_dir_size_add(zfs_dsl_dir_t * dir,uint64_t bytes)427 dsl_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 */
437 void
dsl_dir_root_finalize(zfs_opt_t * zfs,uint64_t bytes)438 dsl_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 */
451 static void
dsl_dir_finalize_props(zfs_dsl_dir_t * dir)452 dsl_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
490 static void
dsl_dir_finalize(zfs_opt_t * zfs,zfs_dsl_dir_t * dir,void * arg __unused)491 dsl_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
548 void
dsl_write(zfs_opt_t * zfs)549 dsl_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
581 void
dsl_dir_dataset_write(zfs_opt_t * zfs,zfs_objset_t * os,zfs_dsl_dir_t * dir)582 dsl_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
588 bool
dsl_dir_has_dataset(zfs_dsl_dir_t * dir)589 dsl_dir_has_dataset(zfs_dsl_dir_t *dir)
590 {
591 return (dir->headds != NULL);
592 }
593
594 bool
dsl_dir_dataset_has_objset(zfs_dsl_dir_t * dir)595 dsl_dir_dataset_has_objset(zfs_dsl_dir_t *dir)
596 {
597 return (dsl_dir_has_dataset(dir) && dir->headds->os != NULL);
598 }
599
600 static zfs_dsl_dataset_t *
dsl_dataset_alloc(zfs_opt_t * zfs,zfs_dsl_dir_t * dir)601 dsl_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