dsl.c 17 KB

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