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(&params, 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