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