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 (void)easprintf(&mountpoint, "%s%s%s", tmp,
123 tmp[strlen(tmp) - 1] == '/' ? "" : "/",
124 origmountpoint);
125 free(tmp);
126 free(origmountpoint);
127 break;
128 }
129
130 (void)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 (void)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 (void)nvlist_add_uint64(nvl, key, 1);
183 else if (strcmp(val, "off") == 0)
184 (void)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 (void)nvlist_add_uint64(nvl, key, 2);
190 else if (strcmp(val, "on") == 0)
191 (void)nvlist_add_uint64(nvl, key, 1);
192 else if (strcmp(val, "off") == 0)
193 (void)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 *
dsl_metadir_alloc(zfs_opt_t * zfs,const char * name)235 dsl_metadir_alloc(zfs_opt_t *zfs, const char *name)
236 {
237 zfs_dsl_dir_t *dir;
238 char *path;
239
240 (void)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
dsl_origindir_init(zfs_opt_t * zfs)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
dsl_init(zfs_opt_t * zfs)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 (void)nvlist_add_uint64(zfs->rootdsldir->propsnv,
326 "compression", ZIO_COMPRESS_OFF);
327 }
328 if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) {
329 (void)nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint",
330 zfs->rootpath);
331 }
332 }
333
334 uint64_t
dsl_dir_id(zfs_dsl_dir_t * dir)335 dsl_dir_id(zfs_dsl_dir_t *dir)
336 {
337 return (dir->dirid);
338 }
339
340 uint64_t
dsl_dir_dataset_id(zfs_dsl_dir_t * dir)341 dsl_dir_dataset_id(zfs_dsl_dir_t *dir)
342 {
343 return (dir->headds->dsid);
344 }
345
346 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)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
dsl_dir_foreach(zfs_opt_t * zfs,zfs_dsl_dir_t * dsldir,void (* cb)(zfs_opt_t *,zfs_dsl_dir_t *,void *),void * arg)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 *
dsl_dir_fullname(const zfs_dsl_dir_t * dir)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 *
dsl_dir_alloc(zfs_opt_t * zfs,const char * name)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 parent = NULL;
435 for (lp = &l;; lp = &parent->children) {
436 dirname = strsep(&nextdir, "/");
437 if (nextdir == NULL)
438 break;
439
440 STAILQ_FOREACH(parent, lp, next) {
441 if (strcmp(parent->name, dirname) == 0)
442 break;
443 }
444 if (parent == NULL) {
445 errx(1, "no parent at `%s' for filesystem `%s'",
446 dirname, name);
447 }
448 }
449
450 dir->fullname = estrdup(name);
451 dir->name = estrdup(dirname);
452 free(origname);
453 STAILQ_INSERT_TAIL(lp, dir, next);
454 zap_add_uint64(parent->childzap, dir->name, dir->dirid);
455
456 dir->parent = parent;
457 dir->phys->dd_parent_obj = parent->dirid;
458 return (dir);
459 }
460
461 static void
dsl_dir_size_add(zfs_dsl_dir_t * dir,uint64_t bytes)462 dsl_dir_size_add(zfs_dsl_dir_t *dir, uint64_t bytes)
463 {
464 dir->phys->dd_used_bytes += bytes;
465 dir->phys->dd_compressed_bytes += bytes;
466 dir->phys->dd_uncompressed_bytes += bytes;
467 }
468
469 /*
470 * See dsl_dir_root_finalize().
471 */
472 void
dsl_dir_root_finalize(zfs_opt_t * zfs,uint64_t bytes)473 dsl_dir_root_finalize(zfs_opt_t *zfs, uint64_t bytes)
474 {
475 dsl_dir_size_add(zfs->mosdsldir, bytes);
476 zfs->mosdsldir->phys->dd_used_breakdown[DD_USED_HEAD] += bytes;
477
478 dsl_dir_size_add(zfs->rootdsldir, bytes);
479 zfs->rootdsldir->phys->dd_used_breakdown[DD_USED_CHILD] += bytes;
480 }
481
482 /*
483 * Convert dataset properties into entries in the DSL directory's properties
484 * ZAP.
485 */
486 static void
dsl_dir_finalize_props(zfs_dsl_dir_t * dir)487 dsl_dir_finalize_props(zfs_dsl_dir_t *dir)
488 {
489 for (nvp_header_t *nvh = NULL;
490 (nvh = nvlist_next_nvpair(dir->propsnv, nvh)) != NULL;) {
491 nv_string_t *nvname;
492 nv_pair_data_t *nvdata;
493 char *name;
494
495 nvname = (nv_string_t *)(nvh + 1);
496 nvdata = (nv_pair_data_t *)(&nvname->nv_data[0] +
497 NV_ALIGN4(nvname->nv_size));
498
499 name = nvstring_get(nvname);
500 switch (nvdata->nv_type) {
501 case DATA_TYPE_UINT64: {
502 uint64_t val;
503
504 memcpy(&val, &nvdata->nv_data[0], sizeof(uint64_t));
505 zap_add_uint64(dir->propszap, name, val);
506 break;
507 }
508 case DATA_TYPE_STRING: {
509 nv_string_t *nvstr;
510 char *val;
511
512 nvstr = (nv_string_t *)&nvdata->nv_data[0];
513 val = nvstring_get(nvstr);
514 zap_add_string(dir->propszap, name, val);
515 free(val);
516 break;
517 }
518 default:
519 assert(0);
520 }
521 free(name);
522 }
523 }
524
525 static void
dsl_dir_finalize(zfs_opt_t * zfs,zfs_dsl_dir_t * dir,void * arg __unused)526 dsl_dir_finalize(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, void *arg __unused)
527 {
528 zfs_dsl_dir_t *cdir;
529 dnode_phys_t *snapnames;
530 zfs_dsl_dataset_t *headds;
531 zfs_objset_t *os;
532 uint64_t bytes, childbytes, snapnamesid;
533
534 dsl_dir_finalize_props(dir);
535 zap_write(zfs, dir->propszap);
536 zap_write(zfs, dir->childzap);
537
538 headds = dir->headds;
539 if (headds == NULL)
540 return;
541 os = headds->os;
542 if (os == NULL)
543 return;
544
545 snapnames = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DS_SNAP_MAP,
546 &snapnamesid);
547 zap_write(zfs, zap_alloc(zfs->mos, snapnames));
548
549 dir->phys->dd_head_dataset_obj = headds->dsid;
550 dir->phys->dd_clone_parent_obj = zfs->snapds->dsid;
551 headds->phys->ds_prev_snap_obj = zfs->snapds->dsid;
552 headds->phys->ds_snapnames_zapobj = snapnamesid;
553 objset_root_blkptr_copy(os, &headds->phys->ds_bp);
554
555 zfs->snapds->phys->ds_num_children++;
556 zap_add_uint64_self(zfs->cloneszap, headds->dsid);
557
558 bytes = objset_space(os);
559 headds->phys->ds_used_bytes = bytes;
560 headds->phys->ds_uncompressed_bytes = bytes;
561 headds->phys->ds_compressed_bytes = bytes;
562
563 childbytes = 0;
564 STAILQ_FOREACH(cdir, &dir->children, next) {
565 /*
566 * The root directory needs a special case: the amount of
567 * space used for the MOS isn't known until everything else is
568 * finalized, so it can't be accounted in the MOS directory's
569 * parent until then, at which point dsl_dir_root_finalize() is
570 * called.
571 */
572 if (dir == zfs->rootdsldir && cdir == zfs->mosdsldir)
573 continue;
574 childbytes += cdir->phys->dd_used_bytes;
575 }
576 dsl_dir_size_add(dir, bytes + childbytes);
577
578 dir->phys->dd_flags |= DD_FLAG_USED_BREAKDOWN;
579 dir->phys->dd_used_breakdown[DD_USED_HEAD] = bytes;
580 dir->phys->dd_used_breakdown[DD_USED_CHILD] = childbytes;
581 }
582
583 void
dsl_write(zfs_opt_t * zfs)584 dsl_write(zfs_opt_t *zfs)
585 {
586 zfs_zap_t *snapnameszap;
587 dnode_phys_t *snapnames;
588 uint64_t snapmapid;
589
590 /*
591 * Perform accounting, starting from the leaves of the DSL directory
592 * tree. Accounting for $MOS is done later, once we've finished
593 * allocating space.
594 */
595 dsl_dir_foreach_post(zfs, zfs->rootdsldir, dsl_dir_finalize, NULL);
596
597 snapnames = objset_dnode_alloc(zfs->mos, DMU_OT_DSL_DS_SNAP_MAP,
598 &snapmapid);
599 snapnameszap = zap_alloc(zfs->mos, snapnames);
600 zap_add_uint64(snapnameszap, "$ORIGIN", zfs->snapds->dsid);
601 zap_write(zfs, snapnameszap);
602
603 zfs->origindsldir->phys->dd_head_dataset_obj = zfs->originds->dsid;
604 zfs->originds->phys->ds_prev_snap_obj = zfs->snapds->dsid;
605 zfs->originds->phys->ds_snapnames_zapobj = snapmapid;
606
607 zfs->snapds->phys->ds_next_snap_obj = zfs->originds->dsid;
608 assert(zfs->snapds->phys->ds_num_children > 0);
609 zfs->snapds->phys->ds_num_children++;
610
611 zap_write(zfs, zfs->cloneszap);
612
613 /* XXX-MJ dirs and datasets are leaked */
614 }
615
616 void
dsl_dir_dataset_write(zfs_opt_t * zfs,zfs_objset_t * os,zfs_dsl_dir_t * dir)617 dsl_dir_dataset_write(zfs_opt_t *zfs, zfs_objset_t *os, zfs_dsl_dir_t *dir)
618 {
619 dir->headds->os = os;
620 objset_write(zfs, os);
621 }
622
623 bool
dsl_dir_has_dataset(zfs_dsl_dir_t * dir)624 dsl_dir_has_dataset(zfs_dsl_dir_t *dir)
625 {
626 return (dir->headds != NULL);
627 }
628
629 bool
dsl_dir_dataset_has_objset(zfs_dsl_dir_t * dir)630 dsl_dir_dataset_has_objset(zfs_dsl_dir_t *dir)
631 {
632 return (dsl_dir_has_dataset(dir) && dir->headds->os != NULL);
633 }
634
635 static zfs_dsl_dataset_t *
dsl_dataset_alloc(zfs_opt_t * zfs,zfs_dsl_dir_t * dir)636 dsl_dataset_alloc(zfs_opt_t *zfs, zfs_dsl_dir_t *dir)
637 {
638 zfs_dsl_dataset_t *ds;
639 dnode_phys_t *dnode;
640 uint64_t deadlistid;
641
642 ds = ecalloc(1, sizeof(*ds));
643
644 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DSL_DATASET,
645 DMU_OT_DSL_DATASET, sizeof(dsl_dataset_phys_t), &ds->dsid);
646 ds->phys = (dsl_dataset_phys_t *)DN_BONUS(dnode);
647
648 dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DEADLIST,
649 DMU_OT_DEADLIST_HDR, sizeof(dsl_deadlist_phys_t), &deadlistid);
650 zap_write(zfs, zap_alloc(zfs->mos, dnode));
651
652 ds->phys->ds_dir_obj = dir->dirid;
653 ds->phys->ds_deadlist_obj = deadlistid;
654 ds->phys->ds_creation_txg = TXG - 1;
655 if (ds != zfs->snapds)
656 ds->phys->ds_prev_snap_txg = TXG - 1;
657 ds->phys->ds_guid = randomguid();
658 ds->dir = dir;
659
660 return (ds);
661 }
662