Print this page
NEX-8972 Async-delete side-effect that may cause unmount EBUSY
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-8466 Failed to do 'pkg update' because of beadm failed to create BE, because of EBUSY in umount
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-8466 Failed to do 'pkg update' because of beadm failed to create BE, because of EBUSY in umount
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-4582 update wrc test cases for allow to use write back cache per tree of datasets
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
5960 zfs recv should prefetch indirect blocks
5925 zfs receive -o origin=
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
NEX-1456 Part 2, port FreeBSD patch - new zfs recv options support
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libbe/common/be_create.c
+++ new/usr/src/lib/libbe/common/be_create.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright (c) 2014, 2015 by Delphix. All rights reserved.
26 26 * Copyright (c) 2016 Martin Matuska. All rights reserved.
27 27 */
28 28
29 29 /*
30 30 * System includes
31 31 */
32 32
33 33 #include <assert.h>
34 34 #include <ctype.h>
35 35 #include <errno.h>
36 36 #include <libgen.h>
37 37 #include <libintl.h>
38 38 #include <libnvpair.h>
39 39 #include <libzfs.h>
40 40 #include <stdio.h>
41 41 #include <stdlib.h>
42 42 #include <string.h>
43 43 #include <sys/mnttab.h>
44 44 #include <sys/mount.h>
45 45 #include <sys/stat.h>
46 46 #include <sys/types.h>
47 47 #include <sys/wait.h>
48 48 #include <unistd.h>
49 49
50 50 #include <libbe.h>
51 51 #include <libbe_priv.h>
52 52
53 53 /* Library wide variables */
54 54 libzfs_handle_t *g_zfs = NULL;
55 55
56 56 /* Private function prototypes */
57 57 static int _be_destroy(const char *, be_destroy_data_t *);
58 58 static int be_destroy_zones(char *, char *, be_destroy_data_t *);
59 59 static int be_destroy_zone_roots(char *, be_destroy_data_t *);
60 60 static int be_destroy_zone_roots_callback(zfs_handle_t *, void *);
61 61 static int be_copy_zones(char *, char *, char *);
62 62 static int be_clone_fs_callback(zfs_handle_t *, void *);
63 63 static int be_destroy_callback(zfs_handle_t *, void *);
64 64 static int be_send_fs_callback(zfs_handle_t *, void *);
65 65 static int be_demote_callback(zfs_handle_t *, void *);
66 66 static int be_demote_find_clone_callback(zfs_handle_t *, void *);
67 67 static int be_has_snapshot_callback(zfs_handle_t *, void *);
68 68 static int be_demote_get_one_clone(zfs_handle_t *, void *);
69 69 static int be_get_snap(char *, char **);
70 70 static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
71 71 char *, int);
72 72 static boolean_t be_create_container_ds(char *);
73 73 static char *be_get_zone_be_name(char *root_ds, char *container_ds);
74 74 static int be_zone_root_exists_callback(zfs_handle_t *, void *);
75 75
76 76 /* ******************************************************************** */
77 77 /* Public Functions */
78 78 /* ******************************************************************** */
79 79
80 80 /*
81 81 * Function: be_init
82 82 * Description: Creates the initial datasets for a BE and leaves them
83 83 * unpopulated. The resultant BE can be mounted but can't
84 84 * yet be activated or booted.
85 85 * Parameters:
86 86 * be_attrs - pointer to nvlist_t of attributes being passed in.
87 87 * The following attributes are used by this function:
88 88 *
89 89 * BE_ATTR_NEW_BE_NAME *required
90 90 * BE_ATTR_NEW_BE_POOL *required
91 91 * BE_ATTR_ZFS_PROPERTIES *optional
92 92 * BE_ATTR_FS_NAMES *optional
93 93 * BE_ATTR_FS_NUM *optional
94 94 * BE_ATTR_SHARED_FS_NAMES *optional
95 95 * BE_ATTR_SHARED_FS_NUM *optional
96 96 * Return:
97 97 * BE_SUCCESS - Success
98 98 * be_errno_t - Failure
99 99 * Scope:
100 100 * Public
101 101 */
102 102 int
103 103 be_init(nvlist_t *be_attrs)
104 104 {
105 105 be_transaction_data_t bt = { 0 };
106 106 zpool_handle_t *zlp;
107 107 nvlist_t *zfs_props = NULL;
108 108 char nbe_root_ds[MAXPATHLEN];
109 109 char child_fs[MAXPATHLEN];
110 110 char **fs_names = NULL;
111 111 char **shared_fs_names = NULL;
112 112 uint16_t fs_num = 0;
113 113 uint16_t shared_fs_num = 0;
114 114 int nelem;
115 115 int i;
116 116 int zret = 0, ret = BE_SUCCESS;
117 117
118 118 /* Initialize libzfs handle */
119 119 if (!be_zfs_init())
120 120 return (BE_ERR_INIT);
121 121
122 122 /* Get new BE name */
123 123 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
124 124 != 0) {
125 125 be_print_err(gettext("be_init: failed to lookup "
126 126 "BE_ATTR_NEW_BE_NAME attribute\n"));
127 127 return (BE_ERR_INVAL);
128 128 }
129 129
130 130 /* Validate new BE name */
131 131 if (!be_valid_be_name(bt.nbe_name)) {
132 132 be_print_err(gettext("be_init: invalid BE name %s\n"),
133 133 bt.nbe_name);
134 134 return (BE_ERR_INVAL);
135 135 }
136 136
137 137 /* Get zpool name */
138 138 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool)
139 139 != 0) {
140 140 be_print_err(gettext("be_init: failed to lookup "
141 141 "BE_ATTR_NEW_BE_POOL attribute\n"));
142 142 return (BE_ERR_INVAL);
143 143 }
144 144
145 145 /* Get file system attributes */
146 146 nelem = 0;
147 147 if (nvlist_lookup_pairs(be_attrs, 0,
148 148 BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num,
149 149 BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem,
150 150 NULL) != 0) {
151 151 be_print_err(gettext("be_init: failed to lookup fs "
152 152 "attributes\n"));
153 153 return (BE_ERR_INVAL);
154 154 }
155 155 if (nelem != fs_num) {
156 156 be_print_err(gettext("be_init: size of FS_NAMES array (%d) "
157 157 "does not match FS_NUM (%d)\n"), nelem, fs_num);
158 158 return (BE_ERR_INVAL);
159 159 }
160 160
161 161 /* Get shared file system attributes */
162 162 nelem = 0;
163 163 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
164 164 BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num,
165 165 BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names,
166 166 &nelem, NULL) != 0) {
167 167 be_print_err(gettext("be_init: failed to lookup "
168 168 "shared fs attributes\n"));
169 169 return (BE_ERR_INVAL);
170 170 }
171 171 if (nelem != shared_fs_num) {
172 172 be_print_err(gettext("be_init: size of SHARED_FS_NAMES "
173 173 "array does not match SHARED_FS_NUM\n"));
174 174 return (BE_ERR_INVAL);
175 175 }
176 176
177 177 /* Verify that nbe_zpool exists */
178 178 if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) {
179 179 be_print_err(gettext("be_init: failed to "
180 180 "find existing zpool (%s): %s\n"), bt.nbe_zpool,
181 181 libzfs_error_description(g_zfs));
182 182 return (zfs_err_to_be_err(g_zfs));
183 183 }
184 184 zpool_close(zlp);
185 185
186 186 /*
187 187 * Verify BE container dataset in nbe_zpool exists.
188 188 * If not, create it.
189 189 */
190 190 if (!be_create_container_ds(bt.nbe_zpool))
191 191 return (BE_ERR_CREATDS);
192 192
193 193 /*
194 194 * Verify that nbe_name doesn't already exist in some pool.
195 195 */
196 196 if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) {
197 197 be_print_err(gettext("be_init: BE (%s) already exists\n"),
198 198 bt.nbe_name);
199 199 return (BE_ERR_BE_EXISTS);
200 200 } else if (zret < 0) {
201 201 be_print_err(gettext("be_init: zpool_iter failed: %s\n"),
202 202 libzfs_error_description(g_zfs));
203 203 return (zfs_err_to_be_err(g_zfs));
204 204 }
205 205
206 206 /* Generate string for BE's root dataset */
207 207 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
208 208 sizeof (nbe_root_ds));
209 209
210 210 /*
211 211 * Create property list for new BE root dataset. If some
212 212 * zfs properties were already provided by the caller, dup
213 213 * that list. Otherwise initialize a new property list.
214 214 */
215 215 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
216 216 BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
217 217 != 0) {
218 218 be_print_err(gettext("be_init: failed to lookup "
219 219 "BE_ATTR_ZFS_PROPERTIES attribute\n"));
220 220 return (BE_ERR_INVAL);
221 221 }
222 222 if (zfs_props != NULL) {
223 223 /* Make sure its a unique nvlist */
224 224 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
225 225 !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
226 226 be_print_err(gettext("be_init: ZFS property list "
227 227 "not unique\n"));
228 228 return (BE_ERR_INVAL);
229 229 }
230 230
231 231 /* Dup the list */
232 232 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
233 233 be_print_err(gettext("be_init: failed to dup ZFS "
234 234 "property list\n"));
235 235 return (BE_ERR_NOMEM);
236 236 }
237 237 } else {
238 238 /* Initialize new nvlist */
239 239 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
240 240 be_print_err(gettext("be_init: internal "
241 241 "error: out of memory\n"));
242 242 return (BE_ERR_NOMEM);
243 243 }
244 244 }
245 245
246 246 /* Set the mountpoint property for the root dataset */
247 247 if (nvlist_add_string(bt.nbe_zfs_props,
248 248 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) {
249 249 be_print_err(gettext("be_init: internal error "
250 250 "out of memory\n"));
251 251 ret = BE_ERR_NOMEM;
252 252 goto done;
253 253 }
254 254
255 255 /* Set the 'canmount' property */
256 256 if (nvlist_add_string(bt.nbe_zfs_props,
257 257 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
258 258 be_print_err(gettext("be_init: internal error "
259 259 "out of memory\n"));
260 260 ret = BE_ERR_NOMEM;
261 261 goto done;
262 262 }
263 263
264 264 /* Create BE root dataset for the new BE */
265 265 if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM,
266 266 bt.nbe_zfs_props) != 0) {
267 267 be_print_err(gettext("be_init: failed to "
268 268 "create BE root dataset (%s): %s\n"), nbe_root_ds,
269 269 libzfs_error_description(g_zfs));
270 270 ret = zfs_err_to_be_err(g_zfs);
271 271 goto done;
272 272 }
273 273
274 274 /* Set UUID for new BE */
275 275 if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) {
276 276 be_print_err(gettext("be_init: failed to "
277 277 "set uuid for new BE\n"));
278 278 }
279 279
280 280 /*
281 281 * Clear the mountpoint property so that the non-shared
282 282 * file systems created below inherit their mountpoints.
283 283 */
284 284 (void) nvlist_remove(bt.nbe_zfs_props,
285 285 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING);
286 286
287 287 /* Create the new BE's non-shared file systems */
288 288 for (i = 0; i < fs_num && fs_names[i]; i++) {
289 289 /*
290 290 * If fs == "/", skip it;
291 291 * we already created the root dataset
292 292 */
293 293 if (strcmp(fs_names[i], "/") == 0)
294 294 continue;
295 295
296 296 /* Generate string for file system */
297 297 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
298 298 nbe_root_ds, fs_names[i]);
299 299
300 300 /* Create file system */
301 301 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
302 302 bt.nbe_zfs_props) != 0) {
303 303 be_print_err(gettext("be_init: failed to create "
304 304 "BE's child dataset (%s): %s\n"), child_fs,
305 305 libzfs_error_description(g_zfs));
306 306 ret = zfs_err_to_be_err(g_zfs);
307 307 goto done;
308 308 }
309 309 }
310 310
311 311 /* Create the new BE's shared file systems */
312 312 if (shared_fs_num > 0) {
313 313 nvlist_t *props = NULL;
314 314
315 315 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
316 316 be_print_err(gettext("be_init: nvlist_alloc failed\n"));
317 317 ret = BE_ERR_NOMEM;
318 318 goto done;
319 319 }
320 320
321 321 for (i = 0; i < shared_fs_num; i++) {
322 322 /* Generate string for shared file system */
323 323 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
324 324 bt.nbe_zpool, shared_fs_names[i]);
325 325
326 326 if (nvlist_add_string(props,
327 327 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
328 328 shared_fs_names[i]) != 0) {
329 329 be_print_err(gettext("be_init: "
330 330 "internal error: out of memory\n"));
331 331 nvlist_free(props);
332 332 ret = BE_ERR_NOMEM;
333 333 goto done;
334 334 }
335 335
336 336 /* Create file system if it doesn't already exist */
337 337 if (zfs_dataset_exists(g_zfs, child_fs,
338 338 ZFS_TYPE_FILESYSTEM)) {
339 339 continue;
340 340 }
341 341 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
342 342 props) != 0) {
343 343 be_print_err(gettext("be_init: failed to "
344 344 "create BE's shared dataset (%s): %s\n"),
345 345 child_fs, libzfs_error_description(g_zfs));
346 346 ret = zfs_err_to_be_err(g_zfs);
347 347 nvlist_free(props);
348 348 goto done;
349 349 }
350 350 }
351 351
352 352 nvlist_free(props);
353 353 }
354 354
355 355 done:
356 356 nvlist_free(bt.nbe_zfs_props);
357 357
358 358 be_zfs_fini();
359 359
360 360 return (ret);
361 361 }
362 362
363 363 /*
364 364 * Function: be_destroy
365 365 * Description: Destroy a BE and all of its children datasets, snapshots and
366 366 * zones that belong to the parent BE.
367 367 * Parameters:
368 368 * be_attrs - pointer to nvlist_t of attributes being passed in.
369 369 * The following attributes are used by this function:
370 370 *
371 371 * BE_ATTR_ORIG_BE_NAME *required
372 372 * BE_ATTR_DESTROY_FLAGS *optional
373 373 * Return:
374 374 * BE_SUCCESS - Success
375 375 * be_errno_t - Failure
376 376 * Scope:
377 377 * Public
378 378 */
379 379 int
380 380 be_destroy(nvlist_t *be_attrs)
381 381 {
382 382 zfs_handle_t *zhp = NULL;
383 383 be_transaction_data_t bt = { 0 };
384 384 be_transaction_data_t cur_bt = { 0 };
385 385 be_destroy_data_t dd = { 0 };
386 386 int ret = BE_SUCCESS;
387 387 uint16_t flags = 0;
388 388 boolean_t bs_found = B_FALSE;
389 389 int zret;
390 390 char obe_root_ds[MAXPATHLEN];
391 391 char *mp = NULL;
392 392
393 393 /* Initialize libzfs handle */
394 394 if (!be_zfs_init())
395 395 return (BE_ERR_INIT);
396 396
397 397 /* Get name of BE to delete */
398 398 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
399 399 != 0) {
400 400 be_print_err(gettext("be_destroy: failed to lookup "
401 401 "BE_ATTR_ORIG_BE_NAME attribute\n"));
402 402 return (BE_ERR_INVAL);
403 403 }
404 404
405 405 /*
406 406 * Validate BE name. If valid, then check that the original BE is not
407 407 * the active BE. If it is the 'active' BE then return an error code
408 408 * since we can't destroy the active BE.
409 409 */
410 410 if (!be_valid_be_name(bt.obe_name)) {
411 411 be_print_err(gettext("be_destroy: invalid BE name %s\n"),
412 412 bt.obe_name);
413 413 return (BE_ERR_INVAL);
414 414 } else if (bt.obe_name != NULL) {
415 415 if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) {
416 416 return (ret);
417 417 }
418 418 if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
419 419 return (BE_ERR_DESTROY_CURR_BE);
420 420 }
421 421 }
422 422
423 423 /* Get destroy flags if provided */
424 424 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
425 425 BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL)
426 426 != 0) {
427 427 be_print_err(gettext("be_destroy: failed to lookup "
428 428 "BE_ATTR_DESTROY_FLAGS attribute\n"));
429 429 return (BE_ERR_INVAL);
430 430 }
431 431
432 432 dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
433 433 dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
434 434
435 435 /* Find which zpool obe_name lives in */
436 436 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
437 437 be_print_err(gettext("be_destroy: failed to find zpool "
438 438 "for BE (%s)\n"), bt.obe_name);
439 439 return (BE_ERR_BE_NOENT);
440 440 } else if (zret < 0) {
441 441 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
442 442 libzfs_error_description(g_zfs));
443 443 return (zfs_err_to_be_err(g_zfs));
444 444 }
445 445
446 446 /* Generate string for obe_name's root dataset */
447 447 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
448 448 sizeof (obe_root_ds));
449 449 bt.obe_root_ds = obe_root_ds;
450 450
451 451 if (getzoneid() != GLOBAL_ZONEID) {
452 452 if (!be_zone_compare_uuids(bt.obe_root_ds)) {
453 453 if (be_is_active_on_boot(bt.obe_name)) {
454 454 be_print_err(gettext("be_destroy: destroying "
455 455 "active zone root dataset from non-active "
456 456 "global BE is not supported\n"));
457 457 return (BE_ERR_NOTSUP);
458 458 }
459 459 }
460 460 }
461 461
462 462 /*
463 463 * Detect if the BE to destroy has the 'active on boot' property set.
464 464 * If so, set the 'active on boot' property on the the 'active' BE.
465 465 */
466 466 if (be_is_active_on_boot(bt.obe_name)) {
467 467 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
468 468 be_print_err(gettext("be_destroy: failed to "
469 469 "make the current BE 'active on boot'\n"));
470 470 return (ret);
471 471 }
472 472 }
473 473
474 474 /* Get handle to BE's root dataset */
475 475 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
476 476 NULL) {
477 477 be_print_err(gettext("be_destroy: failed to "
478 478 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
479 479 libzfs_error_description(g_zfs));
480 480 return (zfs_err_to_be_err(g_zfs));
481 481 }
482 482
483 483 /*
484 484 * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
485 485 * is not set.
486 486 */
487 487 (void) zfs_iter_snapshots(zhp, B_FALSE, be_has_snapshot_callback,
488 488 &bs_found);
489 489 if (!dd.destroy_snaps && bs_found) {
490 490 ZFS_CLOSE(zhp);
491 491 return (BE_ERR_SS_EXISTS);
492 492 }
493 493
494 494 /* Get the UUID of the global BE */
495 495 if (getzoneid() == GLOBAL_ZONEID) {
496 496 if (be_get_uuid(zfs_get_name(zhp),
497 497 &dd.gz_be_uuid) != BE_SUCCESS) {
498 498 be_print_err(gettext("be_destroy: BE has no "
499 499 "UUID (%s)\n"), zfs_get_name(zhp));
500 500 }
501 501 }
502 502
503 503 /*
504 504 * If the global BE is mounted, make sure we've been given the
505 505 * flag to forcibly unmount it.
506 506 */
507 507 if (zfs_is_mounted(zhp, &mp)) {
508 508 if (!(dd.force_unmount)) {
509 509 be_print_err(gettext("be_destroy: "
510 510 "%s is currently mounted at %s, cannot destroy\n"),
511 511 bt.obe_name, mp != NULL ? mp : "<unknown>");
512 512
513 513 free(mp);
514 514 ZFS_CLOSE(zhp);
515 515 return (BE_ERR_MOUNTED);
516 516 }
517 517 free(mp);
518 518 }
519 519
520 520 /*
521 521 * Destroy the non-global zone BE's if we are in the global zone
522 522 * and there is a UUID associated with the global zone BE
523 523 */
524 524 if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) {
525 525 if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd))
526 526 != BE_SUCCESS) {
527 527 be_print_err(gettext("be_destroy: failed to "
528 528 "destroy one or more zones for BE %s\n"),
529 529 bt.obe_name);
530 530 goto done;
531 531 }
532 532 }
533 533
534 534 /* Unmount the BE if it was mounted */
535 535 if (zfs_is_mounted(zhp, NULL)) {
536 536 if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE))
537 537 != BE_SUCCESS) {
538 538 be_print_err(gettext("be_destroy: "
539 539 "failed to unmount %s\n"), bt.obe_name);
540 540 ZFS_CLOSE(zhp);
541 541 return (ret);
542 542 }
543 543 }
544 544 ZFS_CLOSE(zhp);
545 545
546 546 /* Destroy this BE */
547 547 if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd))
548 548 != BE_SUCCESS) {
549 549 goto done;
550 550 }
551 551
552 552 /* Remove BE's entry from the boot menu */
553 553 if (getzoneid() == GLOBAL_ZONEID) {
554 554 if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL))
555 555 != BE_SUCCESS) {
556 556 be_print_err(gettext("be_destroy: failed to "
557 557 "remove BE %s from the boot menu\n"),
558 558 bt.obe_root_ds);
559 559 goto done;
560 560 }
561 561 }
562 562
563 563 done:
564 564 be_zfs_fini();
565 565
566 566 return (ret);
567 567 }
568 568
569 569 /*
570 570 * Function: be_copy
571 571 * Description: This function makes a copy of an existing BE. If the original
572 572 * BE and the new BE are in the same pool, it uses zfs cloning to
573 573 * create the new BE, otherwise it does a physical copy.
574 574 * If the original BE name isn't provided, it uses the currently
575 575 * booted BE. If the new BE name isn't provided, it creates an
576 576 * auto named BE and returns that name to the caller.
577 577 * Parameters:
578 578 * be_attrs - pointer to nvlist_t of attributes being passed in.
579 579 * The following attributes are used by this function:
580 580 *
581 581 * BE_ATTR_ORIG_BE_NAME *optional
582 582 * BE_ATTR_SNAP_NAME *optional
583 583 * BE_ATTR_NEW_BE_NAME *optional
584 584 * BE_ATTR_NEW_BE_POOL *optional
585 585 * BE_ATTR_NEW_BE_DESC *optional
586 586 * BE_ATTR_ZFS_PROPERTIES *optional
587 587 * BE_ATTR_POLICY *optional
588 588 *
589 589 * If the BE_ATTR_NEW_BE_NAME was not passed in, upon
590 590 * successful BE creation, the following attribute values
591 591 * will be returned to the caller by setting them in the
592 592 * be_attrs parameter passed in:
593 593 *
594 594 * BE_ATTR_SNAP_NAME
595 595 * BE_ATTR_NEW_BE_NAME
596 596 * Return:
597 597 * BE_SUCCESS - Success
598 598 * be_errno_t - Failure
599 599 * Scope:
600 600 * Public
601 601 */
602 602 int
603 603 be_copy(nvlist_t *be_attrs)
604 604 {
605 605 be_transaction_data_t bt = { 0 };
606 606 be_fs_list_data_t fld = { 0 };
607 607 zfs_handle_t *zhp = NULL;
608 608 zpool_handle_t *zphp = NULL;
609 609 nvlist_t *zfs_props = NULL;
610 610 uuid_t uu = { 0 };
611 611 uuid_t parent_uu = { 0 };
612 612 char obe_root_ds[MAXPATHLEN];
613 613 char nbe_root_ds[MAXPATHLEN];
614 614 char ss[MAXPATHLEN];
615 615 char *new_mp = NULL;
616 616 char *obe_name = NULL;
617 617 boolean_t autoname = B_FALSE;
618 618 boolean_t be_created = B_FALSE;
619 619 int i;
620 620 int zret;
621 621 int ret = BE_SUCCESS;
622 622 struct be_defaults be_defaults;
623 623
624 624 /* Initialize libzfs handle */
625 625 if (!be_zfs_init())
626 626 return (BE_ERR_INIT);
627 627
628 628 /* Get original BE name */
629 629 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
630 630 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
631 631 be_print_err(gettext("be_copy: failed to lookup "
632 632 "BE_ATTR_ORIG_BE_NAME attribute\n"));
633 633 return (BE_ERR_INVAL);
634 634 }
635 635
636 636 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
637 637 return (ret);
638 638 }
639 639
640 640 be_get_defaults(&be_defaults);
641 641
642 642 /* If original BE name not provided, use current BE */
643 643 if (obe_name != NULL) {
644 644 bt.obe_name = obe_name;
645 645 /* Validate original BE name */
646 646 if (!be_valid_be_name(bt.obe_name)) {
647 647 be_print_err(gettext("be_copy: "
648 648 "invalid BE name %s\n"), bt.obe_name);
649 649 return (BE_ERR_INVAL);
650 650 }
651 651 }
652 652
653 653 if (be_defaults.be_deflt_rpool_container) {
654 654 if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
655 655 be_print_err(gettext("be_get_node_data: failed to "
656 656 "open rpool (%s): %s\n"), bt.obe_zpool,
657 657 libzfs_error_description(g_zfs));
658 658 return (zfs_err_to_be_err(g_zfs));
659 659 }
660 660 if (be_find_zpool_callback(zphp, &bt) == 0) {
661 661 return (BE_ERR_BE_NOENT);
662 662 }
663 663 } else {
664 664 /* Find which zpool obe_name lives in */
665 665 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
666 666 0) {
667 667 be_print_err(gettext("be_copy: failed to "
668 668 "find zpool for BE (%s)\n"), bt.obe_name);
669 669 return (BE_ERR_BE_NOENT);
670 670 } else if (zret < 0) {
671 671 be_print_err(gettext("be_copy: "
672 672 "zpool_iter failed: %s\n"),
673 673 libzfs_error_description(g_zfs));
674 674 return (zfs_err_to_be_err(g_zfs));
675 675 }
676 676 }
677 677
678 678 /* Get snapshot name of original BE if one was provided */
679 679 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
680 680 BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL)
681 681 != 0) {
682 682 be_print_err(gettext("be_copy: failed to lookup "
683 683 "BE_ATTR_SNAP_NAME attribute\n"));
684 684 return (BE_ERR_INVAL);
685 685 }
686 686
687 687 /* Get new BE name */
688 688 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
689 689 BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL)
690 690 != 0) {
691 691 be_print_err(gettext("be_copy: failed to lookup "
692 692 "BE_ATTR_NEW_BE_NAME attribute\n"));
693 693 return (BE_ERR_INVAL);
694 694 }
695 695
696 696 /* Get zpool name to create new BE in */
697 697 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
698 698 BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) {
699 699 be_print_err(gettext("be_copy: failed to lookup "
700 700 "BE_ATTR_NEW_BE_POOL attribute\n"));
701 701 return (BE_ERR_INVAL);
702 702 }
703 703
704 704 /* Get new BE's description if one was provided */
705 705 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
706 706 BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) {
707 707 be_print_err(gettext("be_copy: failed to lookup "
708 708 "BE_ATTR_NEW_BE_DESC attribute\n"));
709 709 return (BE_ERR_INVAL);
710 710 }
711 711
712 712 /* Get BE policy to create this snapshot under */
713 713 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
714 714 BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) {
715 715 be_print_err(gettext("be_copy: failed to lookup "
716 716 "BE_ATTR_POLICY attribute\n"));
717 717 return (BE_ERR_INVAL);
718 718 }
719 719
720 720 /*
721 721 * Create property list for new BE root dataset. If some
722 722 * zfs properties were already provided by the caller, dup
723 723 * that list. Otherwise initialize a new property list.
724 724 */
725 725 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
726 726 BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
727 727 != 0) {
728 728 be_print_err(gettext("be_copy: failed to lookup "
729 729 "BE_ATTR_ZFS_PROPERTIES attribute\n"));
730 730 return (BE_ERR_INVAL);
731 731 }
732 732 if (zfs_props != NULL) {
733 733 /* Make sure its a unique nvlist */
734 734 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
735 735 !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
736 736 be_print_err(gettext("be_copy: ZFS property list "
737 737 "not unique\n"));
738 738 return (BE_ERR_INVAL);
739 739 }
740 740
741 741 /* Dup the list */
742 742 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
743 743 be_print_err(gettext("be_copy: "
744 744 "failed to dup ZFS property list\n"));
745 745 return (BE_ERR_NOMEM);
746 746 }
747 747 } else {
748 748 /* Initialize new nvlist */
749 749 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
750 750 be_print_err(gettext("be_copy: internal "
751 751 "error: out of memory\n"));
752 752 return (BE_ERR_NOMEM);
753 753 }
754 754 }
755 755
756 756 /*
757 757 * If new BE name provided, validate the BE name and then verify
758 758 * that new BE name doesn't already exist in some pool.
759 759 */
760 760 if (bt.nbe_name) {
761 761 /* Validate original BE name */
762 762 if (!be_valid_be_name(bt.nbe_name)) {
763 763 be_print_err(gettext("be_copy: "
764 764 "invalid BE name %s\n"), bt.nbe_name);
765 765 ret = BE_ERR_INVAL;
766 766 goto done;
767 767 }
768 768
769 769 /* Verify it doesn't already exist */
770 770 if (getzoneid() == GLOBAL_ZONEID) {
771 771 if ((zret = zpool_iter(g_zfs, be_exists_callback,
772 772 bt.nbe_name)) > 0) {
773 773 be_print_err(gettext("be_copy: BE (%s) already "
774 774 "exists\n"), bt.nbe_name);
775 775 ret = BE_ERR_BE_EXISTS;
776 776 goto done;
777 777 } else if (zret < 0) {
778 778 be_print_err(gettext("be_copy: zpool_iter "
779 779 "failed: %s\n"),
780 780 libzfs_error_description(g_zfs));
781 781 ret = zfs_err_to_be_err(g_zfs);
782 782 goto done;
783 783 }
784 784 } else {
785 785 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
786 786 sizeof (nbe_root_ds));
787 787 if (zfs_dataset_exists(g_zfs, nbe_root_ds,
788 788 ZFS_TYPE_FILESYSTEM)) {
789 789 be_print_err(gettext("be_copy: BE (%s) already "
790 790 "exists\n"), bt.nbe_name);
791 791 ret = BE_ERR_BE_EXISTS;
792 792 goto done;
793 793 }
794 794 }
795 795 } else {
796 796 /*
797 797 * If an auto named BE is desired, it must be in the same
798 798 * pool is the original BE.
799 799 */
800 800 if (bt.nbe_zpool != NULL) {
801 801 be_print_err(gettext("be_copy: cannot specify pool "
802 802 "name when creating an auto named BE\n"));
803 803 ret = BE_ERR_INVAL;
804 804 goto done;
805 805 }
806 806
807 807 /*
808 808 * Generate auto named BE
809 809 */
810 810 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
811 811 == NULL) {
812 812 be_print_err(gettext("be_copy: "
813 813 "failed to generate auto BE name\n"));
814 814 ret = BE_ERR_AUTONAME;
815 815 goto done;
816 816 }
817 817
818 818 autoname = B_TRUE;
819 819 }
820 820
821 821 /*
822 822 * If zpool name to create new BE in is not provided,
823 823 * create new BE in original BE's pool.
824 824 */
825 825 if (bt.nbe_zpool == NULL) {
826 826 bt.nbe_zpool = bt.obe_zpool;
827 827 }
828 828
829 829 /* Get root dataset names for obe_name and nbe_name */
830 830 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
831 831 sizeof (obe_root_ds));
832 832 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
833 833 sizeof (nbe_root_ds));
834 834
835 835 bt.obe_root_ds = obe_root_ds;
836 836 bt.nbe_root_ds = nbe_root_ds;
837 837
838 838 /*
839 839 * If an existing snapshot name has been provided to create from,
840 840 * verify that it exists for the original BE's root dataset.
841 841 */
842 842 if (bt.obe_snap_name != NULL) {
843 843
844 844 /* Generate dataset name for snapshot to use. */
845 845 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
846 846 bt.obe_snap_name);
847 847
848 848 /* Verify snapshot exists */
849 849 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
850 850 be_print_err(gettext("be_copy: "
851 851 "snapshot does not exist (%s): %s\n"), ss,
852 852 libzfs_error_description(g_zfs));
853 853 ret = BE_ERR_SS_NOENT;
854 854 goto done;
855 855 }
856 856 } else {
857 857 /*
858 858 * Else snapshot name was not provided, generate an
859 859 * auto named snapshot to use as its origin.
860 860 */
861 861 if ((ret = _be_create_snapshot(bt.obe_name,
862 862 &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) {
863 863 be_print_err(gettext("be_copy: "
864 864 "failed to create auto named snapshot\n"));
865 865 goto done;
866 866 }
867 867
868 868 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
869 869 bt.obe_snap_name) != 0) {
870 870 be_print_err(gettext("be_copy: "
871 871 "failed to add snap name to be_attrs\n"));
872 872 ret = BE_ERR_NOMEM;
873 873 goto done;
874 874 }
875 875 }
876 876
877 877 /* Get handle to original BE's root dataset. */
878 878 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
879 879 == NULL) {
880 880 be_print_err(gettext("be_copy: failed to "
881 881 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
882 882 libzfs_error_description(g_zfs));
883 883 ret = zfs_err_to_be_err(g_zfs);
884 884 goto done;
885 885 }
886 886
887 887 /* If original BE is currently mounted, record its altroot. */
888 888 if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) {
889 889 be_print_err(gettext("be_copy: failed to "
890 890 "get altroot of mounted BE %s: %s\n"),
891 891 bt.obe_name, libzfs_error_description(g_zfs));
892 892 ret = zfs_err_to_be_err(g_zfs);
893 893 goto done;
894 894 }
895 895
896 896 if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) {
897 897
898 898 /* Do clone */
899 899
900 900 /*
901 901 * Iterate through original BE's datasets and clone
902 902 * them to create new BE. This call will end up closing
903 903 * the zfs handle passed in whether it succeeds for fails.
904 904 */
905 905 if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) {
906 906 zhp = NULL;
907 907 /* Creating clone BE failed */
908 908 if (!autoname || ret != BE_ERR_BE_EXISTS) {
909 909 be_print_err(gettext("be_copy: "
910 910 "failed to clone new BE (%s) from "
911 911 "orig BE (%s)\n"),
912 912 bt.nbe_name, bt.obe_name);
913 913 ret = BE_ERR_CLONE;
914 914 goto done;
915 915 }
916 916
917 917 /*
918 918 * We failed to create the new BE because a BE with
919 919 * the auto-name we generated above has since come
920 920 * into existence. Regenerate a new auto-name
921 921 * and retry.
922 922 */
923 923 for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
924 924
925 925 /* Sleep 1 before retrying */
926 926 (void) sleep(1);
927 927
928 928 /* Generate new auto BE name */
929 929 free(bt.nbe_name);
930 930 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
931 931 == NULL) {
932 932 be_print_err(gettext("be_copy: "
933 933 "failed to generate auto "
934 934 "BE name\n"));
935 935 ret = BE_ERR_AUTONAME;
936 936 goto done;
937 937 }
938 938
939 939 /*
940 940 * Regenerate string for new BE's
941 941 * root dataset name
942 942 */
943 943 be_make_root_ds(bt.nbe_zpool, bt.nbe_name,
944 944 nbe_root_ds, sizeof (nbe_root_ds));
945 945 bt.nbe_root_ds = nbe_root_ds;
946 946
947 947 /*
948 948 * Get handle to original BE's root dataset.
949 949 */
950 950 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds,
951 951 ZFS_TYPE_FILESYSTEM)) == NULL) {
952 952 be_print_err(gettext("be_copy: "
953 953 "failed to open BE root dataset "
954 954 "(%s): %s\n"), bt.obe_root_ds,
955 955 libzfs_error_description(g_zfs));
956 956 ret = zfs_err_to_be_err(g_zfs);
957 957 goto done;
958 958 }
959 959
960 960 /*
961 961 * Try to clone the BE again. This
962 962 * call will end up closing the zfs
963 963 * handle passed in whether it
964 964 * succeeds or fails.
965 965 */
966 966 ret = be_clone_fs_callback(zhp, &bt);
967 967 zhp = NULL;
968 968 if (ret == 0) {
969 969 break;
970 970 } else if (ret != BE_ERR_BE_EXISTS) {
971 971 be_print_err(gettext("be_copy: "
972 972 "failed to clone new BE "
973 973 "(%s) from orig BE (%s)\n"),
974 974 bt.nbe_name, bt.obe_name);
975 975 ret = BE_ERR_CLONE;
976 976 goto done;
977 977 }
978 978 }
979 979
980 980 /*
981 981 * If we've exhausted the maximum number of
982 982 * tries, free the auto BE name and return
983 983 * error.
984 984 */
985 985 if (i == BE_AUTO_NAME_MAX_TRY) {
986 986 be_print_err(gettext("be_copy: failed "
987 987 "to create unique auto BE name\n"));
988 988 free(bt.nbe_name);
989 989 bt.nbe_name = NULL;
990 990 ret = BE_ERR_AUTONAME;
991 991 goto done;
992 992 }
993 993 }
994 994 zhp = NULL;
995 995
996 996 } else {
997 997
998 998 /* Do copy (i.e. send BE datasets via zfs_send/recv) */
999 999
1000 1000 /*
1001 1001 * Verify BE container dataset in nbe_zpool exists.
1002 1002 * If not, create it.
1003 1003 */
1004 1004 if (!be_create_container_ds(bt.nbe_zpool)) {
1005 1005 ret = BE_ERR_CREATDS;
1006 1006 goto done;
1007 1007 }
1008 1008
1009 1009 /*
1010 1010 * Iterate through original BE's datasets and send
1011 1011 * them to the other pool. This call will end up closing
1012 1012 * the zfs handle passed in whether it succeeds or fails.
1013 1013 */
1014 1014 if ((ret = be_send_fs_callback(zhp, &bt)) != 0) {
1015 1015 be_print_err(gettext("be_copy: failed to "
1016 1016 "send BE (%s) to pool (%s)\n"), bt.obe_name,
1017 1017 bt.nbe_zpool);
1018 1018 ret = BE_ERR_COPY;
1019 1019 zhp = NULL;
1020 1020 goto done;
1021 1021 }
1022 1022 zhp = NULL;
1023 1023 }
1024 1024
1025 1025 /*
1026 1026 * Set flag to note that the dataset(s) for the new BE have been
1027 1027 * successfully created so that if a failure happens from this point
1028 1028 * on, we know to cleanup these datasets.
1029 1029 */
1030 1030 be_created = B_TRUE;
1031 1031
1032 1032 /*
1033 1033 * Validate that the new BE is mountable.
1034 1034 * Do not attempt to mount non-global zone datasets
1035 1035 * since they are not cloned yet.
1036 1036 */
1037 1037 if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1038 1038 != BE_SUCCESS) {
1039 1039 be_print_err(gettext("be_copy: failed to "
1040 1040 "mount newly created BE\n"));
1041 1041 (void) _be_unmount(bt.nbe_name, 0);
1042 1042 goto done;
1043 1043 }
1044 1044
1045 1045 /* Set UUID for new BE */
1046 1046 if (getzoneid() == GLOBAL_ZONEID) {
1047 1047 if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
1048 1048 be_print_err(gettext("be_copy: failed to "
1049 1049 "set uuid for new BE\n"));
1050 1050 }
1051 1051 } else {
1052 1052 if ((ret = be_zone_get_parent_uuid(bt.obe_root_ds,
1053 1053 &parent_uu)) != BE_SUCCESS) {
1054 1054 be_print_err(gettext("be_copy: failed to get "
1055 1055 "parentbe uuid from orig BE\n"));
1056 1056 ret = BE_ERR_ZONE_NO_PARENTBE;
1057 1057 goto done;
1058 1058 } else if ((ret = be_zone_set_parent_uuid(bt.nbe_root_ds,
1059 1059 parent_uu)) != BE_SUCCESS) {
1060 1060 be_print_err(gettext("be_copy: failed to set "
1061 1061 "parentbe uuid for newly created BE\n"));
1062 1062 goto done;
1063 1063 }
1064 1064 }
1065 1065
1066 1066 /*
1067 1067 * Process zones outside of the private BE namespace.
1068 1068 * This has to be done here because we need the uuid set in the
1069 1069 * root dataset of the new BE. The uuid is use to set the parentbe
1070 1070 * property for the new zones datasets.
1071 1071 */
1072 1072 if (getzoneid() == GLOBAL_ZONEID &&
1073 1073 be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1074 1074 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1075 1075 bt.nbe_root_ds)) != BE_SUCCESS) {
1076 1076 be_print_err(gettext("be_copy: failed to process "
1077 1077 "zones\n"));
1078 1078 goto done;
1079 1079 }
1080 1080 }
1081 1081
1082 1082 /*
1083 1083 * Generate a list of file systems from the original BE that are
1084 1084 * legacy mounted. We use this list to determine which entries in
1085 1085 * vfstab we need to update for the new BE we've just created.
1086 1086 */
1087 1087 if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
1088 1088 &fld)) != BE_SUCCESS) {
1089 1089 be_print_err(gettext("be_copy: failed to "
1090 1090 "get legacy mounted file system list for %s\n"),
1091 1091 bt.obe_name);
1092 1092 goto done;
1093 1093 }
1094 1094
1095 1095 /*
1096 1096 * Update new BE's vfstab.
1097 1097 */
1098 1098 if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
1099 1099 &fld, new_mp)) != BE_SUCCESS) {
1100 1100 be_print_err(gettext("be_copy: failed to "
1101 1101 "update new BE's vfstab (%s)\n"), bt.nbe_name);
1102 1102 goto done;
1103 1103 }
1104 1104
1105 1105 /* Unmount the new BE */
1106 1106 if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) {
1107 1107 be_print_err(gettext("be_copy: failed to "
1108 1108 "unmount newly created BE\n"));
1109 1109 goto done;
1110 1110 }
1111 1111
1112 1112 /*
1113 1113 * Add boot menu entry for newly created clone
1114 1114 */
1115 1115 if (getzoneid() == GLOBAL_ZONEID &&
1116 1116 (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool,
1117 1117 NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) {
1118 1118 be_print_err(gettext("be_copy: failed to "
1119 1119 "add BE (%s) to boot menu\n"), bt.nbe_name);
1120 1120 goto done;
1121 1121 }
1122 1122
1123 1123 /*
1124 1124 * If we succeeded in creating an auto named BE, set its policy
1125 1125 * type and return the auto generated name to the caller by storing
1126 1126 * it in the nvlist passed in by the caller.
1127 1127 */
1128 1128 if (autoname) {
1129 1129 /* Get handle to new BE's root dataset. */
1130 1130 if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds,
1131 1131 ZFS_TYPE_FILESYSTEM)) == NULL) {
1132 1132 be_print_err(gettext("be_copy: failed to "
1133 1133 "open BE root dataset (%s): %s\n"), bt.nbe_root_ds,
1134 1134 libzfs_error_description(g_zfs));
1135 1135 ret = zfs_err_to_be_err(g_zfs);
1136 1136 goto done;
1137 1137 }
1138 1138
1139 1139 /*
1140 1140 * Set the policy type property into the new BE's root dataset
1141 1141 */
1142 1142 if (bt.policy == NULL) {
1143 1143 /* If no policy type provided, use default type */
1144 1144 bt.policy = be_default_policy();
1145 1145 }
1146 1146
1147 1147 if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) {
1148 1148 be_print_err(gettext("be_copy: failed to "
1149 1149 "set BE policy for %s: %s\n"), bt.nbe_name,
1150 1150 libzfs_error_description(g_zfs));
1151 1151 ret = zfs_err_to_be_err(g_zfs);
1152 1152 goto done;
1153 1153 }
1154 1154
1155 1155 /*
1156 1156 * Return the auto generated name to the caller
1157 1157 */
1158 1158 if (bt.nbe_name) {
1159 1159 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME,
1160 1160 bt.nbe_name) != 0) {
1161 1161 be_print_err(gettext("be_copy: failed to "
1162 1162 "add snap name to be_attrs\n"));
1163 1163 }
1164 1164 }
1165 1165 }
1166 1166
1167 1167 done:
1168 1168 ZFS_CLOSE(zhp);
1169 1169 be_free_fs_list(&fld);
1170 1170
1171 1171 nvlist_free(bt.nbe_zfs_props);
1172 1172
1173 1173 free(bt.obe_altroot);
1174 1174 free(new_mp);
1175 1175
1176 1176 /*
1177 1177 * If a failure occurred and we already created the datasets for
1178 1178 * the new boot environment, destroy them.
1179 1179 */
1180 1180 if (ret != BE_SUCCESS && be_created) {
1181 1181 be_destroy_data_t cdd = { 0 };
1182 1182
1183 1183 cdd.force_unmount = B_TRUE;
1184 1184
1185 1185 be_print_err(gettext("be_copy: "
1186 1186 "destroying partially created boot environment\n"));
1187 1187
1188 1188 if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds,
1189 1189 &cdd.gz_be_uuid) == 0)
1190 1190 (void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds,
1191 1191 &cdd);
1192 1192
1193 1193 (void) _be_destroy(bt.nbe_root_ds, &cdd);
1194 1194 }
1195 1195
1196 1196 be_zfs_fini();
1197 1197
1198 1198 return (ret);
1199 1199 }
1200 1200
1201 1201 /* ******************************************************************** */
1202 1202 /* Semi-Private Functions */
1203 1203 /* ******************************************************************** */
1204 1204
1205 1205 /*
1206 1206 * Function: be_find_zpool_callback
1207 1207 * Description: Callback function used to find the pool that a BE lives in.
1208 1208 * Parameters:
1209 1209 * zlp - zpool_handle_t pointer for the current pool being
1210 1210 * looked at.
1211 1211 * data - be_transaction_data_t pointer providing information
1212 1212 * about the BE that's being searched for.
1213 1213 * This function uses the obe_name member of this
1214 1214 * parameter to use as the BE name to search for.
1215 1215 * Upon successfully locating the BE, it populates
1216 1216 * obe_zpool with the pool name that the BE is found in.
1217 1217 * Returns:
1218 1218 * 1 - BE exists in this pool.
1219 1219 * 0 - BE does not exist in this pool.
1220 1220 * Scope:
1221 1221 * Semi-private (library wide use only)
1222 1222 */
1223 1223 int
1224 1224 be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1225 1225 {
1226 1226 be_transaction_data_t *bt = data;
1227 1227 const char *zpool = zpool_get_name(zlp);
1228 1228 char be_root_ds[MAXPATHLEN];
1229 1229
1230 1230 /*
1231 1231 * Generate string for the BE's root dataset
1232 1232 */
1233 1233 be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1234 1234
1235 1235 /*
1236 1236 * Check if dataset exists
1237 1237 */
1238 1238 if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1239 1239 /* BE's root dataset exists in zpool */
1240 1240 bt->obe_zpool = strdup(zpool);
1241 1241 zpool_close(zlp);
1242 1242 return (1);
1243 1243 }
1244 1244
1245 1245 zpool_close(zlp);
1246 1246 return (0);
1247 1247 }
1248 1248
1249 1249 /*
1250 1250 * Function: be_exists_callback
1251 1251 * Description: Callback function used to find out if a BE exists.
1252 1252 * Parameters:
1253 1253 * zlp - zpool_handle_t pointer to the current pool being
1254 1254 * looked at.
1255 1255 * data - BE name to look for.
1256 1256 * Return:
1257 1257 * 1 - BE exists in this pool.
1258 1258 * 0 - BE does not exist in this pool.
1259 1259 * Scope:
1260 1260 * Semi-private (library wide use only)
1261 1261 */
1262 1262 int
1263 1263 be_exists_callback(zpool_handle_t *zlp, void *data)
1264 1264 {
1265 1265 const char *zpool = zpool_get_name(zlp);
1266 1266 char *be_name = data;
1267 1267 char be_root_ds[MAXPATHLEN];
1268 1268
1269 1269 /*
1270 1270 * Generate string for the BE's root dataset
1271 1271 */
1272 1272 be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1273 1273
1274 1274 /*
1275 1275 * Check if dataset exists
1276 1276 */
1277 1277 if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1278 1278 /* BE's root dataset exists in zpool */
1279 1279 zpool_close(zlp);
1280 1280 return (1);
1281 1281 }
1282 1282
1283 1283 zpool_close(zlp);
1284 1284 return (0);
1285 1285 }
1286 1286
1287 1287 /*
1288 1288 * Function: be_has_snapshots_callback
1289 1289 * Description: Callback function used to find out if a BE has snapshots.
1290 1290 * Parameters:
1291 1291 * zlp - zpool_handle_t pointer to the current pool being
1292 1292 * looked at.
1293 1293 * data - be_snap_found_t pointer.
1294 1294 * Return:
1295 1295 * 1 - BE has no snapshots.
1296 1296 * 0 - BE has snapshots.
1297 1297 * Scope:
1298 1298 * Private
1299 1299 */
1300 1300 static int
1301 1301 be_has_snapshot_callback(zfs_handle_t *zhp, void *data)
1302 1302 {
1303 1303 boolean_t *bs = data;
1304 1304 if (zfs_get_name(zhp) == NULL) {
1305 1305 zfs_close(zhp);
1306 1306 return (1);
1307 1307 }
1308 1308 *bs = B_TRUE;
1309 1309 zfs_close(zhp);
1310 1310 return (0);
1311 1311 }
1312 1312
1313 1313 /*
1314 1314 * Function: be_set_uuid
1315 1315 * Description: This function generates a uuid, unparses it into
1316 1316 * string representation, and sets that string into
1317 1317 * a zfs user property for a root dataset of a BE.
1318 1318 * The name of the user property used to store the
1319 1319 * uuid is org.opensolaris.libbe:uuid
1320 1320 *
1321 1321 * Parameters:
1322 1322 * root_ds - Root dataset of the BE to set a uuid on.
1323 1323 * Return:
1324 1324 * be_errno_t - Failure
1325 1325 * BE_SUCCESS - Success
1326 1326 * Scope:
1327 1327 * Semi-private (library wide ues only)
1328 1328 */
1329 1329 int
1330 1330 be_set_uuid(char *root_ds)
1331 1331 {
1332 1332 zfs_handle_t *zhp = NULL;
1333 1333 uuid_t uu = { 0 };
1334 1334 char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1335 1335 int ret = BE_SUCCESS;
1336 1336
1337 1337 /* Generate a UUID and unparse it into string form */
1338 1338 uuid_generate(uu);
1339 1339 if (uuid_is_null(uu) != 0) {
1340 1340 be_print_err(gettext("be_set_uuid: failed to "
1341 1341 "generate uuid\n"));
1342 1342 return (BE_ERR_GEN_UUID);
1343 1343 }
1344 1344 uuid_unparse(uu, uu_string);
1345 1345
1346 1346 /* Get handle to the BE's root dataset. */
1347 1347 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1348 1348 be_print_err(gettext("be_set_uuid: failed to "
1349 1349 "open BE root dataset (%s): %s\n"), root_ds,
1350 1350 libzfs_error_description(g_zfs));
1351 1351 return (zfs_err_to_be_err(g_zfs));
1352 1352 }
1353 1353
1354 1354 /* Set uuid property for the BE */
1355 1355 if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) {
1356 1356 be_print_err(gettext("be_set_uuid: failed to "
1357 1357 "set uuid property for BE: %s\n"),
1358 1358 libzfs_error_description(g_zfs));
1359 1359 ret = zfs_err_to_be_err(g_zfs);
1360 1360 }
1361 1361
1362 1362 ZFS_CLOSE(zhp);
1363 1363
1364 1364 return (ret);
1365 1365 }
1366 1366
1367 1367 /*
1368 1368 * Function: be_get_uuid
1369 1369 * Description: This function gets the uuid string from a BE root
1370 1370 * dataset, parses it into internal format, and returns
1371 1371 * it the caller via a reference pointer passed in.
1372 1372 *
1373 1373 * Parameters:
1374 1374 * rootds - Root dataset of the BE to get the uuid from.
1375 1375 * uu - reference pointer to a uuid_t to return uuid in.
1376 1376 * Return:
1377 1377 * be_errno_t - Failure
1378 1378 * BE_SUCCESS - Success
1379 1379 * Scope:
1380 1380 * Semi-private (library wide use only)
1381 1381 */
1382 1382 int
1383 1383 be_get_uuid(const char *root_ds, uuid_t *uu)
1384 1384 {
1385 1385 zfs_handle_t *zhp = NULL;
1386 1386 nvlist_t *userprops = NULL;
1387 1387 nvlist_t *propname = NULL;
1388 1388 char *uu_string = NULL;
1389 1389 int ret = BE_SUCCESS;
1390 1390
1391 1391 /* Get handle to the BE's root dataset. */
1392 1392 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1393 1393 be_print_err(gettext("be_get_uuid: failed to "
1394 1394 "open BE root dataset (%s): %s\n"), root_ds,
1395 1395 libzfs_error_description(g_zfs));
1396 1396 return (zfs_err_to_be_err(g_zfs));
1397 1397 }
1398 1398
1399 1399 /* Get user properties for BE's root dataset */
1400 1400 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1401 1401 be_print_err(gettext("be_get_uuid: failed to "
1402 1402 "get user properties for BE root dataset (%s): %s\n"),
1403 1403 root_ds, libzfs_error_description(g_zfs));
1404 1404 ret = zfs_err_to_be_err(g_zfs);
1405 1405 goto done;
1406 1406 }
1407 1407
1408 1408 /* Get UUID string from BE's root dataset user properties */
1409 1409 if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 ||
1410 1410 nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) {
1411 1411 /*
1412 1412 * This probably just means that the BE is simply too old
1413 1413 * to have a uuid or that we haven't created a uuid for
1414 1414 * this BE yet.
1415 1415 */
1416 1416 be_print_err(gettext("be_get_uuid: failed to "
1417 1417 "get uuid property from BE root dataset user "
1418 1418 "properties.\n"));
1419 1419 ret = BE_ERR_NO_UUID;
1420 1420 goto done;
1421 1421 }
1422 1422 /* Parse uuid string into internal format */
1423 1423 if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
1424 1424 be_print_err(gettext("be_get_uuid: failed to "
1425 1425 "parse uuid\n"));
1426 1426 ret = BE_ERR_PARSE_UUID;
1427 1427 goto done;
1428 1428 }
1429 1429
1430 1430 done:
1431 1431 ZFS_CLOSE(zhp);
1432 1432 return (ret);
1433 1433 }
1434 1434
1435 1435 /* ******************************************************************** */
1436 1436 /* Private Functions */
1437 1437 /* ******************************************************************** */
1438 1438
1439 1439 /*
1440 1440 * Function: _be_destroy
1441 1441 * Description: Destroy a BE and all of its children datasets and snapshots.
1442 1442 * This function is called for both global BEs and non-global BEs.
1443 1443 * The root dataset of either the global BE or non-global BE to be
1444 1444 * destroyed is passed in.
1445 1445 * Parameters:
1446 1446 * root_ds - pointer to the name of the root dataset of the
1447 1447 * BE to destroy.
1448 1448 * dd - pointer to a be_destroy_data_t structure.
1449 1449 *
1450 1450 * Return:
1451 1451 * BE_SUCCESS - Success
1452 1452 * be_errno_t - Failure
1453 1453 * Scope:
1454 1454 * Private
1455 1455 */
1456 1456 static int
1457 1457 _be_destroy(const char *root_ds, be_destroy_data_t *dd)
1458 1458 {
1459 1459 zfs_handle_t *zhp = NULL;
1460 1460 char origin[MAXPATHLEN];
1461 1461 char parent[MAXPATHLEN];
1462 1462 char *snap = NULL;
1463 1463 boolean_t has_origin = B_FALSE;
1464 1464 int ret = BE_SUCCESS;
1465 1465
1466 1466 /* Get handle to BE's root dataset */
1467 1467 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1468 1468 NULL) {
1469 1469 be_print_err(gettext("be_destroy: failed to "
1470 1470 "open BE root dataset (%s): %s\n"), root_ds,
1471 1471 libzfs_error_description(g_zfs));
1472 1472 return (zfs_err_to_be_err(g_zfs));
1473 1473 }
1474 1474
1475 1475 /*
1476 1476 * Demote this BE in case it has dependent clones. This call
1477 1477 * will end up closing the zfs handle passed in whether it
1478 1478 * succeeds or fails.
1479 1479 */
1480 1480 if (be_demote_callback(zhp, NULL) != 0) {
1481 1481 be_print_err(gettext("be_destroy: "
1482 1482 "failed to demote BE %s\n"), root_ds);
1483 1483 return (BE_ERR_DEMOTE);
1484 1484 }
1485 1485
1486 1486 /* Get handle to BE's root dataset */
1487 1487 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1488 1488 NULL) {
1489 1489 be_print_err(gettext("be_destroy: failed to "
1490 1490 "open BE root dataset (%s): %s\n"), root_ds,
1491 1491 libzfs_error_description(g_zfs));
1492 1492 return (zfs_err_to_be_err(g_zfs));
1493 1493 }
1494 1494
1495 1495 /*
1496 1496 * Get the origin of this BE's root dataset. This will be used
1497 1497 * later to destroy the snapshots originally used to create this BE.
1498 1498 */
1499 1499 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1500 1500 NULL, 0, B_FALSE) == 0) {
1501 1501 (void) strlcpy(parent, origin, sizeof (parent));
1502 1502 if (be_get_snap(parent, &snap) != BE_SUCCESS) {
1503 1503 ZFS_CLOSE(zhp);
1504 1504 be_print_err(gettext("be_destroy: failed to "
1505 1505 "get snapshot name from origin %s\n"), origin);
1506 1506 return (BE_ERR_INVAL);
1507 1507 }
1508 1508 has_origin = B_TRUE;
1509 1509 }
1510 1510
1511 1511 /*
1512 1512 * Destroy the BE's root and its hierarchical children. This call
1513 1513 * will end up closing the zfs handle passed in whether it succeeds
1514 1514 * or fails.
1515 1515 */
1516 1516 if (be_destroy_callback(zhp, dd) != 0) {
1517 1517 be_print_err(gettext("be_destroy: failed to "
1518 1518 "destroy BE %s\n"), root_ds);
1519 1519 ret = zfs_err_to_be_err(g_zfs);
1520 1520 return (ret);
1521 1521 }
1522 1522
1523 1523 /* If BE has an origin */
1524 1524 if (has_origin) {
1525 1525
1526 1526 /*
1527 1527 * If origin snapshot doesn't have any other
1528 1528 * dependents, delete the origin.
1529 1529 */
1530 1530 if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) ==
1531 1531 NULL) {
1532 1532 be_print_err(gettext("be_destroy: failed to "
1533 1533 "open BE's origin (%s): %s\n"), origin,
1534 1534 libzfs_error_description(g_zfs));
1535 1535 ret = zfs_err_to_be_err(g_zfs);
1536 1536 return (ret);
1537 1537 }
1538 1538
1539 1539 /* If origin has dependents, don't delete it. */
1540 1540 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
1541 1541 ZFS_CLOSE(zhp);
1542 1542 return (ret);
1543 1543 }
1544 1544 ZFS_CLOSE(zhp);
1545 1545
1546 1546 /* Get handle to BE's parent's root dataset */
1547 1547 if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) ==
1548 1548 NULL) {
1549 1549 be_print_err(gettext("be_destroy: failed to "
1550 1550 "open BE's parent root dataset (%s): %s\n"), parent,
1551 1551 libzfs_error_description(g_zfs));
1552 1552 ret = zfs_err_to_be_err(g_zfs);
1553 1553 return (ret);
1554 1554 }
1555 1555
1556 1556 /* Destroy the snapshot origin used to create this BE. */
1557 1557 /*
1558 1558 * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
1559 1559 * tells zfs to process and destroy the snapshots now.
1560 1560 * Otherwise the call will potentially return where the
1561 1561 * snapshot isn't actually destroyed yet, and ZFS is waiting
1562 1562 * until all the references to the snapshot have been
1563 1563 * released before actually destroying the snapshot.
1564 1564 */
1565 1565 if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) {
1566 1566 be_print_err(gettext("be_destroy: failed to "
1567 1567 "destroy original snapshots used to create "
1568 1568 "BE: %s\n"), libzfs_error_description(g_zfs));
1569 1569
1570 1570 /*
1571 1571 * If a failure happened because a clone exists,
1572 1572 * don't return a failure to the user. Above, we're
1573 1573 * only checking that the root dataset's origin
1574 1574 * snapshot doesn't have dependent clones, but its
1575 1575 * possible that a subordinate dataset origin snapshot
1576 1576 * has a clone. We really need to check for that
1577 1577 * before trying to destroy the origin snapshot.
1578 1578 */
1579 1579 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1580 1580 ret = zfs_err_to_be_err(g_zfs);
1581 1581 ZFS_CLOSE(zhp);
1582 1582 return (ret);
1583 1583 }
1584 1584 }
1585 1585 ZFS_CLOSE(zhp);
1586 1586 }
1587 1587
1588 1588 return (ret);
1589 1589 }
1590 1590
1591 1591 /*
1592 1592 * Function: be_destroy_zones
1593 1593 * Description: Find valid zone's and call be_destroy_zone_roots to destroy its
1594 1594 * corresponding dataset and all of its children datasets
1595 1595 * and snapshots.
1596 1596 * Parameters:
1597 1597 * be_name - name of global boot environment being destroyed
1598 1598 * be_root_ds - root dataset of global boot environment being
1599 1599 * destroyed.
1600 1600 * dd - be_destroy_data_t pointer
1601 1601 * Return:
1602 1602 * BE_SUCCESS - Success
1603 1603 * be_errno_t - Failure
1604 1604 * Scope:
1605 1605 * Private
1606 1606 *
1607 1607 * NOTES - Requires that the BE being deleted has no dependent BEs. If it
1608 1608 * does, the destroy will fail.
1609 1609 */
1610 1610 static int
1611 1611 be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1612 1612 {
1613 1613 int i;
1614 1614 int ret = BE_SUCCESS;
1615 1615 int force_umnt = BE_UNMOUNT_FLAG_NULL;
1616 1616 char *zonepath = NULL;
1617 1617 char *zonename = NULL;
1618 1618 char *zonepath_ds = NULL;
1619 1619 char *mp = NULL;
1620 1620 zoneList_t zlist = NULL;
1621 1621 zoneBrandList_t *brands = NULL;
1622 1622 zfs_handle_t *zhp = NULL;
1623 1623
1624 1624 /* If zones are not implemented, then get out. */
1625 1625 if (!z_zones_are_implemented()) {
1626 1626 return (BE_SUCCESS);
1627 1627 }
1628 1628
1629 1629 /* Get list of supported brands */
1630 1630 if ((brands = be_get_supported_brandlist()) == NULL) {
1631 1631 be_print_err(gettext("be_destroy_zones: "
1632 1632 "no supported brands\n"));
1633 1633 return (BE_SUCCESS);
1634 1634 }
1635 1635
1636 1636 /* Get handle to BE's root dataset */
1637 1637 if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1638 1638 NULL) {
1639 1639 be_print_err(gettext("be_destroy_zones: failed to "
1640 1640 "open BE root dataset (%s): %s\n"), be_root_ds,
1641 1641 libzfs_error_description(g_zfs));
1642 1642 z_free_brand_list(brands);
1643 1643 return (zfs_err_to_be_err(g_zfs));
1644 1644 }
1645 1645
1646 1646 /*
1647 1647 * If the global BE is not mounted, we must mount it here to
1648 1648 * gather data about the non-global zones in it.
1649 1649 */
1650 1650 if (!zfs_is_mounted(zhp, &mp)) {
1651 1651 if ((ret = _be_mount(be_name, &mp,
1652 1652 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1653 1653 be_print_err(gettext("be_destroy_zones: failed to "
1654 1654 "mount the BE (%s) for zones processing.\n"),
1655 1655 be_name);
1656 1656 ZFS_CLOSE(zhp);
1657 1657 z_free_brand_list(brands);
1658 1658 return (ret);
1659 1659 }
1660 1660 }
1661 1661 ZFS_CLOSE(zhp);
1662 1662
1663 1663 z_set_zone_root(mp);
1664 1664 free(mp);
1665 1665
1666 1666 /* Get list of supported zones. */
1667 1667 if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1668 1668 z_free_brand_list(brands);
1669 1669 return (BE_SUCCESS);
1670 1670 }
1671 1671
1672 1672 /* Unmount the BE before destroying the zones in it. */
1673 1673 if (dd->force_unmount)
1674 1674 force_umnt = BE_UNMOUNT_FLAG_FORCE;
1675 1675 if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1676 1676 be_print_err(gettext("be_destroy_zones: failed to "
1677 1677 "unmount the BE (%s)\n"), be_name);
1678 1678 goto done;
1679 1679 }
1680 1680
1681 1681 /* Iterate through the zones and destroy them. */
1682 1682 for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1683 1683
1684 1684 /* Skip zones that aren't at least installed */
1685 1685 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1686 1686 continue;
1687 1687
1688 1688 zonepath = z_zlist_get_zonepath(zlist, i);
1689 1689
1690 1690 /*
1691 1691 * Get the dataset of this zonepath. If its not
1692 1692 * a dataset, skip it.
1693 1693 */
1694 1694 if ((zonepath_ds = be_get_ds_from_dir(zonepath)) == NULL)
1695 1695 continue;
1696 1696
1697 1697 /*
1698 1698 * Check if this zone is supported based on the
1699 1699 * dataset of its zonepath.
1700 1700 */
1701 1701 if (!be_zone_supported(zonepath_ds)) {
1702 1702 free(zonepath_ds);
1703 1703 continue;
1704 1704 }
1705 1705
1706 1706 /* Find the zone BE root datasets for this zone. */
1707 1707 if ((ret = be_destroy_zone_roots(zonepath_ds, dd))
1708 1708 != BE_SUCCESS) {
1709 1709 be_print_err(gettext("be_destroy_zones: failed to "
1710 1710 "find and destroy zone roots for zone %s\n"),
1711 1711 zonename);
1712 1712 free(zonepath_ds);
1713 1713 goto done;
1714 1714 }
1715 1715 free(zonepath_ds);
1716 1716 }
1717 1717
1718 1718 done:
1719 1719 z_free_brand_list(brands);
1720 1720 z_free_zone_list(zlist);
1721 1721
1722 1722 return (ret);
1723 1723 }
1724 1724
1725 1725 /*
1726 1726 * Function: be_destroy_zone_roots
1727 1727 * Description: This function will open the zone's root container dataset
1728 1728 * and iterate the datasets within, looking for roots that
1729 1729 * belong to the given global BE and destroying them.
1730 1730 * If no other zone roots remain in the zone's root container
1731 1731 * dataset, the function will destroy it and the zone's
1732 1732 * zonepath dataset as well.
1733 1733 * Parameters:
1734 1734 * zonepath_ds - pointer to zone's zonepath dataset.
1735 1735 * dd - pointer to a linked destroy data.
1736 1736 * Returns:
1737 1737 * BE_SUCCESS - Success
1738 1738 * be_errno_t - Failure
1739 1739 * Scope:
1740 1740 * Private
1741 1741 */
1742 1742 static int
1743 1743 be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1744 1744 {
1745 1745 zfs_handle_t *zhp;
1746 1746 char zone_container_ds[MAXPATHLEN];
1747 1747 int ret = BE_SUCCESS;
1748 1748
1749 1749 /* Generate string for the root container dataset for this zone. */
1750 1750 be_make_container_ds(zonepath_ds, zone_container_ds,
1751 1751 sizeof (zone_container_ds));
1752 1752
1753 1753 /* Get handle to this zone's root container dataset. */
1754 1754 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1755 1755 == NULL) {
1756 1756 be_print_err(gettext("be_destroy_zone_roots: failed to "
1757 1757 "open zone root container dataset (%s): %s\n"),
1758 1758 zone_container_ds, libzfs_error_description(g_zfs));
1759 1759 return (zfs_err_to_be_err(g_zfs));
1760 1760 }
1761 1761
1762 1762 /*
1763 1763 * Iterate through all of this zone's BEs, destroying the ones
1764 1764 * that belong to the parent global BE.
1765 1765 */
1766 1766 if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1767 1767 dd)) != 0) {
1768 1768 be_print_err(gettext("be_destroy_zone_roots: failed to "
1769 1769 "destroy zone roots under zonepath dataset %s: %s\n"),
1770 1770 zonepath_ds, libzfs_error_description(g_zfs));
1771 1771 ZFS_CLOSE(zhp);
1772 1772 return (ret);
1773 1773 }
1774 1774 ZFS_CLOSE(zhp);
1775 1775
1776 1776 /* Get handle to this zone's root container dataset. */
1777 1777 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1778 1778 == NULL) {
1779 1779 be_print_err(gettext("be_destroy_zone_roots: failed to "
1780 1780 "open zone root container dataset (%s): %s\n"),
1781 1781 zone_container_ds, libzfs_error_description(g_zfs));
1782 1782 return (zfs_err_to_be_err(g_zfs));
1783 1783 }
1784 1784
1785 1785 /*
1786 1786 * If there are no more zone roots in this zone's root container,
1787 1787 * dataset, destroy it and the zonepath dataset as well.
1788 1788 */
1789 1789 if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1790 1790 == 0) {
1791 1791 /* Destroy the zone root container dataset */
1792 1792 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1793 1793 zfs_destroy(zhp, B_FALSE) != 0) {
1794 1794 be_print_err(gettext("be_destroy_zone_roots: failed to "
1795 1795 "destroy zone root container dataset (%s): %s\n"),
1796 1796 zone_container_ds, libzfs_error_description(g_zfs));
1797 1797 goto done;
1798 1798 }
1799 1799 ZFS_CLOSE(zhp);
1800 1800
1801 1801 /* Get handle to zonepath dataset */
1802 1802 if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1803 1803 == NULL) {
1804 1804 be_print_err(gettext("be_destroy_zone_roots: failed to "
1805 1805 "open zonepath dataset (%s): %s\n"),
1806 1806 zonepath_ds, libzfs_error_description(g_zfs));
1807 1807 goto done;
1808 1808 }
1809 1809
1810 1810 /* Destroy zonepath dataset */
1811 1811 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1812 1812 zfs_destroy(zhp, B_FALSE) != 0) {
1813 1813 be_print_err(gettext("be_destroy_zone_roots: "
1814 1814 "failed to destroy zonepath dataest %s: %s\n"),
1815 1815 zonepath_ds, libzfs_error_description(g_zfs));
1816 1816 goto done;
1817 1817 }
1818 1818 }
1819 1819
1820 1820 done:
1821 1821 ZFS_CLOSE(zhp);
1822 1822 return (ret);
1823 1823 }
1824 1824
1825 1825 /*
1826 1826 * Function: be_destroy_zone_roots_callback
1827 1827 * Description: This function is used as a callback to iterate over all of
1828 1828 * a zone's root datasets, finding the one's that
1829 1829 * correspond to the current BE. The name's
1830 1830 * of the zone root datasets are then destroyed by _be_destroy().
1831 1831 * Parameters:
1832 1832 * zhp - zfs_handle_t pointer to current dataset being processed
1833 1833 * data - be_destroy_data_t pointer
1834 1834 * Returns:
1835 1835 * 0 - Success
1836 1836 * be_errno_t - Failure
1837 1837 * Scope:
1838 1838 * Private
1839 1839 */
1840 1840 static int
1841 1841 be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1842 1842 {
1843 1843 be_destroy_data_t *dd = data;
1844 1844 uuid_t parent_uuid = { 0 };
1845 1845 int ret = 0;
1846 1846
1847 1847 if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1848 1848 != BE_SUCCESS) {
1849 1849 be_print_err(gettext("be_destroy_zone_roots_callback: "
1850 1850 "could not get parentuuid for zone root dataset %s\n"),
1851 1851 zfs_get_name(zhp));
1852 1852 ZFS_CLOSE(zhp);
1853 1853 return (0);
1854 1854 }
1855 1855
1856 1856 if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1857 1857 /*
1858 1858 * Found a zone root dataset belonging to the parent
1859 1859 * BE being destroyed. Destroy this zone BE.
1860 1860 */
1861 1861 if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1862 1862 be_print_err(gettext("be_destroy_zone_root_callback: "
1863 1863 "failed to destroy zone root %s\n"),
1864 1864 zfs_get_name(zhp));
1865 1865 ZFS_CLOSE(zhp);
1866 1866 return (ret);
1867 1867 }
1868 1868 }
1869 1869 ZFS_CLOSE(zhp);
1870 1870
1871 1871 return (ret);
1872 1872 }
1873 1873
1874 1874 /*
1875 1875 * Function: be_copy_zones
1876 1876 * Description: Find valid zones and clone them to create their
1877 1877 * corresponding datasets for the BE being created.
1878 1878 * Parameters:
1879 1879 * obe_name - name of source global BE being copied.
1880 1880 * obe_root_ds - root dataset of source global BE being copied.
1881 1881 * nbe_root_ds - root dataset of target global BE.
1882 1882 * Return:
1883 1883 * BE_SUCCESS - Success
1884 1884 * be_errno_t - Failure
1885 1885 * Scope:
1886 1886 * Private
1887 1887 */
1888 1888 static int
1889 1889 be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1890 1890 {
1891 1891 int i, num_retries;
1892 1892 int ret = BE_SUCCESS;
1893 1893 int iret = 0;
1894 1894 char *zonename = NULL;
1895 1895 char *zonepath = NULL;
1896 1896 char *zone_be_name = NULL;
1897 1897 char *temp_mntpt = NULL;
1898 1898 char *new_zone_be_name = NULL;
1899 1899 char zoneroot[MAXPATHLEN];
1900 1900 char zoneroot_ds[MAXPATHLEN];
1901 1901 char zone_container_ds[MAXPATHLEN];
1902 1902 char new_zoneroot_ds[MAXPATHLEN];
1903 1903 char ss[MAXPATHLEN];
1904 1904 uuid_t uu = { 0 };
1905 1905 char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1906 1906 be_transaction_data_t bt = { 0 };
1907 1907 zfs_handle_t *obe_zhp = NULL;
1908 1908 zfs_handle_t *nbe_zhp = NULL;
1909 1909 zfs_handle_t *z_zhp = NULL;
1910 1910 zoneList_t zlist = NULL;
1911 1911 zoneBrandList_t *brands = NULL;
1912 1912 boolean_t mounted_here = B_FALSE;
1913 1913 char *snap_name = NULL;
1914 1914
1915 1915 /* If zones are not implemented, then get out. */
1916 1916 if (!z_zones_are_implemented()) {
1917 1917 return (BE_SUCCESS);
1918 1918 }
1919 1919
1920 1920 /* Get list of supported brands */
1921 1921 if ((brands = be_get_supported_brandlist()) == NULL) {
1922 1922 be_print_err(gettext("be_copy_zones: "
1923 1923 "no supported brands\n"));
1924 1924 return (BE_SUCCESS);
1925 1925 }
1926 1926
1927 1927 /* Get handle to origin BE's root dataset */
1928 1928 if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1929 1929 == NULL) {
1930 1930 be_print_err(gettext("be_copy_zones: failed to open "
1931 1931 "the origin BE root dataset (%s) for zones processing: "
1932 1932 "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1933 1933 return (zfs_err_to_be_err(g_zfs));
1934 1934 }
1935 1935
1936 1936 /* Get handle to newly cloned BE's root dataset */
1937 1937 if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1938 1938 == NULL) {
1939 1939 be_print_err(gettext("be_copy_zones: failed to open "
1940 1940 "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1941 1941 libzfs_error_description(g_zfs));
1942 1942 ZFS_CLOSE(obe_zhp);
1943 1943 return (zfs_err_to_be_err(g_zfs));
1944 1944 }
1945 1945
1946 1946 /* Get the uuid of the newly cloned parent BE. */
1947 1947 if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1948 1948 be_print_err(gettext("be_copy_zones: "
1949 1949 "failed to get uuid for BE root "
1950 1950 "dataset %s\n"), zfs_get_name(nbe_zhp));
1951 1951 ZFS_CLOSE(nbe_zhp);
1952 1952 goto done;
1953 1953 }
1954 1954 ZFS_CLOSE(nbe_zhp);
1955 1955 uuid_unparse(uu, uu_string);
1956 1956
1957 1957 /*
1958 1958 * If the origin BE is not mounted, we must mount it here to
1959 1959 * gather data about the non-global zones in it.
1960 1960 */
1961 1961 if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1962 1962 if ((ret = _be_mount(obe_name, &temp_mntpt,
1963 1963 BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1964 1964 be_print_err(gettext("be_copy_zones: failed to "
1965 1965 "mount the BE (%s) for zones procesing.\n"),
1966 1966 obe_name);
1967 1967 goto done;
1968 1968 }
1969 1969 mounted_here = B_TRUE;
1970 1970 }
1971 1971
1972 1972 z_set_zone_root(temp_mntpt);
1973 1973
1974 1974 /* Get list of supported zones. */
1975 1975 if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1976 1976 ret = BE_SUCCESS;
1977 1977 goto done;
1978 1978 }
1979 1979
1980 1980 for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1981 1981
1982 1982 be_fs_list_data_t fld = { 0 };
1983 1983 char zonepath_ds[MAXPATHLEN];
1984 1984 char *ds = NULL;
1985 1985
1986 1986 /* Get zonepath of zone */
1987 1987 zonepath = z_zlist_get_zonepath(zlist, i);
1988 1988
1989 1989 /* Skip zones that aren't at least installed */
1990 1990 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1991 1991 continue;
1992 1992
1993 1993 /*
1994 1994 * Get the dataset of this zonepath. If its not
1995 1995 * a dataset, skip it.
1996 1996 */
1997 1997 if ((ds = be_get_ds_from_dir(zonepath)) == NULL)
1998 1998 continue;
1999 1999
2000 2000 (void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
2001 2001 free(ds);
2002 2002 ds = NULL;
2003 2003
2004 2004 /* Get zoneroot directory */
2005 2005 be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2006 2006
2007 2007 /* If zonepath dataset not supported, skip it. */
2008 2008 if (!be_zone_supported(zonepath_ds)) {
2009 2009 continue;
2010 2010 }
2011 2011
2012 2012 if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
2013 2013 zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
2014 2014 be_print_err(gettext("be_copy_zones: "
2015 2015 "failed to find active zone root for zone %s "
2016 2016 "in BE %s\n"), zonename, obe_name);
2017 2017 goto done;
2018 2018 }
2019 2019
2020 2020 be_make_container_ds(zonepath_ds, zone_container_ds,
2021 2021 sizeof (zone_container_ds));
2022 2022
2023 2023 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2024 2024 ZFS_TYPE_FILESYSTEM)) == NULL) {
2025 2025 be_print_err(gettext("be_copy_zones: "
2026 2026 "failed to open zone root dataset (%s): %s\n"),
2027 2027 zoneroot_ds, libzfs_error_description(g_zfs));
2028 2028 ret = zfs_err_to_be_err(g_zfs);
2029 2029 goto done;
2030 2030 }
2031 2031
2032 2032 zone_be_name =
2033 2033 be_get_zone_be_name(zoneroot_ds, zone_container_ds);
2034 2034
2035 2035 if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
2036 2036 zone_be_name)) == NULL) {
2037 2037 be_print_err(gettext("be_copy_zones: failed "
2038 2038 "to generate auto name for zone BE.\n"));
2039 2039 ret = BE_ERR_AUTONAME;
2040 2040 goto done;
2041 2041 }
2042 2042
2043 2043 if ((snap_name = be_auto_snap_name()) == NULL) {
2044 2044 be_print_err(gettext("be_copy_zones: failed to "
2045 2045 "generate snapshot name for zone BE.\n"));
2046 2046 ret = BE_ERR_AUTONAME;
2047 2047 goto done;
2048 2048 }
2049 2049
2050 2050 (void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
2051 2051 snap_name);
2052 2052
2053 2053 if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
2054 2054 be_print_err(gettext("be_copy_zones: "
2055 2055 "failed to snapshot zone BE (%s): %s\n"),
2056 2056 ss, libzfs_error_description(g_zfs));
2057 2057 if (libzfs_errno(g_zfs) == EZFS_EXISTS)
2058 2058 ret = BE_ERR_ZONE_SS_EXISTS;
2059 2059 else
2060 2060 ret = zfs_err_to_be_err(g_zfs);
2061 2061
2062 2062 goto done;
2063 2063 }
2064 2064
2065 2065 (void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
2066 2066 "%s/%s", zone_container_ds, new_zone_be_name);
2067 2067
2068 2068 bt.obe_name = zone_be_name;
2069 2069 bt.obe_root_ds = zoneroot_ds;
2070 2070 bt.obe_snap_name = snap_name;
2071 2071 bt.obe_altroot = temp_mntpt;
2072 2072 bt.nbe_name = new_zone_be_name;
2073 2073 bt.nbe_root_ds = new_zoneroot_ds;
2074 2074
2075 2075 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
2076 2076 be_print_err(gettext("be_copy_zones: "
2077 2077 "internal error: out of memory\n"));
2078 2078 ret = BE_ERR_NOMEM;
2079 2079 goto done;
2080 2080 }
2081 2081
2082 2082 /*
2083 2083 * The call to be_clone_fs_callback always closes the
2084 2084 * zfs_handle so there's no need to close z_zhp.
2085 2085 */
2086 2086 if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
2087 2087 z_zhp = NULL;
2088 2088 if (iret != BE_ERR_BE_EXISTS) {
2089 2089 be_print_err(gettext("be_copy_zones: "
2090 2090 "failed to create zone BE clone for new "
2091 2091 "zone BE %s\n"), new_zone_be_name);
2092 2092 ret = iret;
2093 2093 nvlist_free(bt.nbe_zfs_props);
2094 2094 goto done;
2095 2095 }
2096 2096 /*
2097 2097 * We failed to create the new zone BE because a zone
2098 2098 * BE with the auto-name we generated above has since
2099 2099 * come into existence. Regenerate a new auto-name
2100 2100 * and retry.
2101 2101 */
2102 2102 for (num_retries = 1;
2103 2103 num_retries < BE_AUTO_NAME_MAX_TRY;
2104 2104 num_retries++) {
2105 2105
2106 2106 /* Sleep 1 before retrying */
2107 2107 (void) sleep(1);
2108 2108
2109 2109 /* Generate new auto zone BE name */
2110 2110 free(new_zone_be_name);
2111 2111 if ((new_zone_be_name = be_auto_zone_be_name(
2112 2112 zone_container_ds,
2113 2113 zone_be_name)) == NULL) {
2114 2114 be_print_err(gettext("be_copy_zones: "
2115 2115 "failed to generate auto name "
2116 2116 "for zone BE.\n"));
2117 2117 ret = BE_ERR_AUTONAME;
2118 2118 nvlist_free(bt.nbe_zfs_props);
2119 2119 goto done;
2120 2120 }
2121 2121
2122 2122 (void) snprintf(new_zoneroot_ds,
2123 2123 sizeof (new_zoneroot_ds),
2124 2124 "%s/%s", zone_container_ds,
2125 2125 new_zone_be_name);
2126 2126 bt.nbe_name = new_zone_be_name;
2127 2127 bt.nbe_root_ds = new_zoneroot_ds;
2128 2128
2129 2129 /*
2130 2130 * Get handle to original zone BE's root
2131 2131 * dataset.
2132 2132 */
2133 2133 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2134 2134 ZFS_TYPE_FILESYSTEM)) == NULL) {
2135 2135 be_print_err(gettext("be_copy_zones: "
2136 2136 "failed to open zone root "
2137 2137 "dataset (%s): %s\n"),
2138 2138 zoneroot_ds,
2139 2139 libzfs_error_description(g_zfs));
2140 2140 ret = zfs_err_to_be_err(g_zfs);
2141 2141 nvlist_free(bt.nbe_zfs_props);
2142 2142 goto done;
2143 2143 }
2144 2144
2145 2145 /*
2146 2146 * Try to clone the zone BE again. This
2147 2147 * call will end up closing the zfs
2148 2148 * handle passed in whether it
2149 2149 * succeeds or fails.
2150 2150 */
2151 2151 iret = be_clone_fs_callback(z_zhp, &bt);
2152 2152 z_zhp = NULL;
2153 2153 if (iret == 0) {
2154 2154 break;
2155 2155 } else if (iret != BE_ERR_BE_EXISTS) {
2156 2156 be_print_err(gettext("be_copy_zones: "
2157 2157 "failed to create zone BE clone "
2158 2158 "for new zone BE %s\n"),
2159 2159 new_zone_be_name);
2160 2160 ret = iret;
2161 2161 nvlist_free(bt.nbe_zfs_props);
2162 2162 goto done;
2163 2163 }
2164 2164 }
2165 2165 /*
2166 2166 * If we've exhausted the maximum number of
2167 2167 * tries, free the auto zone BE name and return
2168 2168 * error.
2169 2169 */
2170 2170 if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2171 2171 be_print_err(gettext("be_copy_zones: failed "
2172 2172 "to create a unique auto zone BE name\n"));
2173 2173 free(bt.nbe_name);
2174 2174 bt.nbe_name = NULL;
2175 2175 ret = BE_ERR_AUTONAME;
2176 2176 nvlist_free(bt.nbe_zfs_props);
2177 2177 goto done;
2178 2178 }
2179 2179 }
2180 2180
2181 2181 nvlist_free(bt.nbe_zfs_props);
2182 2182
2183 2183 z_zhp = NULL;
2184 2184
2185 2185 if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2186 2186 ZFS_TYPE_FILESYSTEM)) == NULL) {
2187 2187 be_print_err(gettext("be_copy_zones: "
2188 2188 "failed to open the new zone BE root dataset "
2189 2189 "(%s): %s\n"), new_zoneroot_ds,
2190 2190 libzfs_error_description(g_zfs));
2191 2191 ret = zfs_err_to_be_err(g_zfs);
2192 2192 goto done;
2193 2193 }
2194 2194
2195 2195 if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2196 2196 uu_string) != 0) {
2197 2197 be_print_err(gettext("be_copy_zones: "
2198 2198 "failed to set parentbe property\n"));
2199 2199 ZFS_CLOSE(z_zhp);
2200 2200 ret = zfs_err_to_be_err(g_zfs);
2201 2201 goto done;
2202 2202 }
2203 2203
2204 2204 if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2205 2205 be_print_err(gettext("be_copy_zones: "
2206 2206 "failed to set active property\n"));
2207 2207 ZFS_CLOSE(z_zhp);
2208 2208 ret = zfs_err_to_be_err(g_zfs);
2209 2209 goto done;
2210 2210 }
2211 2211
2212 2212 /*
2213 2213 * Generate a list of file systems from the original
2214 2214 * zone BE that are legacy mounted. We use this list
2215 2215 * to determine which entries in the vfstab we need to
2216 2216 * update for the new zone BE we've just created.
2217 2217 */
2218 2218 if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2219 2219 zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2220 2220 be_print_err(gettext("be_copy_zones: "
2221 2221 "failed to get legacy mounted file system "
2222 2222 "list for zone %s\n"), zonename);
2223 2223 ZFS_CLOSE(z_zhp);
2224 2224 goto done;
2225 2225 }
2226 2226
2227 2227 /*
2228 2228 * Update new zone BE's vfstab.
2229 2229 */
2230 2230 if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2231 2231 zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2232 2232 be_print_err(gettext("be_copy_zones: "
2233 2233 "failed to update new BE's vfstab (%s)\n"),
2234 2234 bt.nbe_name);
2235 2235 ZFS_CLOSE(z_zhp);
2236 2236 be_free_fs_list(&fld);
2237 2237 goto done;
2238 2238 }
2239 2239
2240 2240 be_free_fs_list(&fld);
2241 2241 ZFS_CLOSE(z_zhp);
2242 2242 }
2243 2243
2244 2244 done:
2245 2245 free(snap_name);
2246 2246 if (brands != NULL)
2247 2247 z_free_brand_list(brands);
2248 2248 if (zlist != NULL)
2249 2249 z_free_zone_list(zlist);
2250 2250
2251 2251 if (mounted_here)
2252 2252 (void) _be_unmount(obe_name, 0);
2253 2253
2254 2254 ZFS_CLOSE(obe_zhp);
2255 2255 return (ret);
2256 2256 }
2257 2257
2258 2258 /*
2259 2259 * Function: be_clone_fs_callback
2260 2260 * Description: Callback function used to iterate through a BE's filesystems
2261 2261 * to clone them for the new BE.
2262 2262 * Parameters:
2263 2263 * zhp - zfs_handle_t pointer for the filesystem being processed.
2264 2264 * data - be_transaction_data_t pointer providing information
2265 2265 * about original BE and new BE.
2266 2266 * Return:
2267 2267 * 0 - Success
2268 2268 * be_errno_t - Failure
2269 2269 * Scope:
2270 2270 * Private
2271 2271 */
2272 2272 static int
2273 2273 be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2274 2274 {
2275 2275 be_transaction_data_t *bt = data;
2276 2276 zfs_handle_t *zhp_ss = NULL;
2277 2277 char prop_buf[MAXPATHLEN];
2278 2278 char zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2279 2279 char clone_ds[MAXPATHLEN];
2280 2280 char ss[MAXPATHLEN];
2281 2281 int ret = 0;
2282 2282
2283 2283 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2284 2284 ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2285 2285 be_print_err(gettext("be_clone_fs_callback: "
2286 2286 "failed to get dataset mountpoint (%s): %s\n"),
2287 2287 zfs_get_name(zhp), libzfs_error_description(g_zfs));
2288 2288 ret = zfs_err_to_be_err(g_zfs);
2289 2289 ZFS_CLOSE(zhp);
2290 2290 return (ret);
2291 2291 }
2292 2292
2293 2293 if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2294 2294 strcmp(prop_buf, "legacy") != 0) {
2295 2295 /*
2296 2296 * Since zfs can't currently handle setting the
2297 2297 * mountpoint for a zoned dataset we'll have to skip
2298 2298 * this dataset. This is because the mountpoint is not
2299 2299 * set to "legacy".
2300 2300 */
2301 2301 goto zoned;
2302 2302 }
2303 2303 /*
2304 2304 * Get a copy of the dataset name from the zfs handle
2305 2305 */
2306 2306 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2307 2307
2308 2308 /*
2309 2309 * Get the clone dataset name and prepare the zfs properties for it.
2310 2310 */
2311 2311 if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2312 2312 sizeof (clone_ds))) != BE_SUCCESS) {
2313 2313 ZFS_CLOSE(zhp);
2314 2314 return (ret);
2315 2315 }
2316 2316
2317 2317 /*
2318 2318 * Generate the name of the snapshot to use.
2319 2319 */
2320 2320 (void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2321 2321 bt->obe_snap_name);
2322 2322
2323 2323 /*
2324 2324 * Get handle to snapshot.
2325 2325 */
2326 2326 if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2327 2327 be_print_err(gettext("be_clone_fs_callback: "
2328 2328 "failed to get handle to snapshot (%s): %s\n"), ss,
2329 2329 libzfs_error_description(g_zfs));
2330 2330 ret = zfs_err_to_be_err(g_zfs);
2331 2331 ZFS_CLOSE(zhp);
2332 2332 return (ret);
2333 2333 }
2334 2334
2335 2335 /*
2336 2336 * Clone the dataset.
2337 2337 */
2338 2338 if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2339 2339 be_print_err(gettext("be_clone_fs_callback: "
2340 2340 "failed to create clone dataset (%s): %s\n"),
2341 2341 clone_ds, libzfs_error_description(g_zfs));
2342 2342
2343 2343 ZFS_CLOSE(zhp_ss);
2344 2344 ZFS_CLOSE(zhp);
2345 2345
2346 2346 return (zfs_err_to_be_err(g_zfs));
2347 2347 }
2348 2348
2349 2349 ZFS_CLOSE(zhp_ss);
2350 2350
2351 2351 zoned:
2352 2352 /*
2353 2353 * Iterate through zhp's children datasets (if any)
2354 2354 * and clone them accordingly.
2355 2355 */
2356 2356 if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2357 2357 /*
2358 2358 * Error occurred while processing a child dataset.
2359 2359 * Destroy this dataset and return error.
2360 2360 */
2361 2361 zfs_handle_t *d_zhp = NULL;
2362 2362
2363 2363 ZFS_CLOSE(zhp);
2364 2364
2365 2365 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2366 2366 == NULL) {
2367 2367 return (ret);
2368 2368 }
2369 2369
2370 2370 (void) zfs_destroy(d_zhp, B_FALSE);
2371 2371 ZFS_CLOSE(d_zhp);
2372 2372 return (ret);
2373 2373 }
2374 2374
2375 2375 ZFS_CLOSE(zhp);
2376 2376 return (0);
2377 2377 }
2378 2378
2379 2379 /*
2380 2380 * Function: be_send_fs_callback
2381 2381 * Description: Callback function used to iterate through a BE's filesystems
2382 2382 * to copy them for the new BE.
2383 2383 * Parameters:
2384 2384 * zhp - zfs_handle_t pointer for the filesystem being processed.
2385 2385 * data - be_transaction_data_t pointer providing information
2386 2386 * about original BE and new BE.
2387 2387 * Return:
2388 2388 * 0 - Success
2389 2389 * be_errnot_t - Failure
2390 2390 * Scope:
2391 2391 * Private
2392 2392 */
2393 2393 static int
2394 2394 be_send_fs_callback(zfs_handle_t *zhp, void *data)
2395 2395 {
2396 2396 be_transaction_data_t *bt = data;
2397 2397 recvflags_t flags = { 0 };
2398 2398 char zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2399 2399 char clone_ds[MAXPATHLEN];
2400 2400 sendflags_t send_flags = { 0 };
2401 2401 int pid, status, retval;
2402 2402 int srpipe[2];
2403 2403 int ret = 0;
2404 2404
2405 2405 /*
2406 2406 * Get a copy of the dataset name from the zfs handle
2407 2407 */
2408 2408 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2409 2409
2410 2410 /*
2411 2411 * Get the clone dataset name and prepare the zfs properties for it.
2412 2412 */
2413 2413 if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2414 2414 sizeof (clone_ds))) != BE_SUCCESS) {
2415 2415 ZFS_CLOSE(zhp);
2416 2416 return (ret);
2417 2417 }
2418 2418
2419 2419 /*
2420 2420 * Create the new dataset.
2421 2421 */
2422 2422 if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2423 2423 != 0) {
2424 2424 be_print_err(gettext("be_send_fs_callback: "
2425 2425 "failed to create new dataset '%s': %s\n"),
2426 2426 clone_ds, libzfs_error_description(g_zfs));
2427 2427 ret = zfs_err_to_be_err(g_zfs);
2428 2428 ZFS_CLOSE(zhp);
2429 2429 return (ret);
2430 2430 }
2431 2431
2432 2432 /*
2433 2433 * Destination file system is already created
2434 2434 * hence we need to set the force flag on
2435 2435 */
2436 2436 flags.force = B_TRUE;
2437 2437
2438 2438 /*
2439 2439 * Initiate the pipe to be used for the send and recv
2440 2440 */
2441 2441 if (pipe(srpipe) != 0) {
2442 2442 int err = errno;
2443 2443 be_print_err(gettext("be_send_fs_callback: failed to "
2444 2444 "open pipe\n"));
2445 2445 ZFS_CLOSE(zhp);
2446 2446 return (errno_to_be_err(err));
2447 2447 }
2448 2448
2449 2449 /*
2450 2450 * Fork off a child to send the dataset
2451 2451 */
2452 2452 if ((pid = fork()) == -1) {
2453 2453 int err = errno;
2454 2454 be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2455 2455 (void) close(srpipe[0]);
2456 2456 (void) close(srpipe[1]);
2457 2457 ZFS_CLOSE(zhp);
2458 2458 return (errno_to_be_err(err));
2459 2459 } else if (pid == 0) { /* child process */
2460 2460 (void) close(srpipe[0]);
2461 2461
2462 2462 /* Send dataset */
2463 2463 if (zfs_send(zhp, NULL, bt->obe_snap_name, &send_flags,
2464 2464 srpipe[1], NULL, NULL, NULL) != 0) {
|
↓ open down ↓ |
2430 lines elided |
↑ open up ↑ |
2465 2465 _exit(1);
2466 2466 }
2467 2467 ZFS_CLOSE(zhp);
2468 2468
2469 2469 _exit(0);
2470 2470 }
2471 2471
2472 2472 (void) close(srpipe[1]);
2473 2473
2474 2474 /* Receive dataset */
2475 - if (zfs_receive(g_zfs, clone_ds, NULL, &flags, srpipe[0], NULL) != 0) {
2475 + if (zfs_receive(g_zfs, clone_ds, &flags, srpipe[0], NULL, NULL,
2476 + NULL) != 0) {
2476 2477 be_print_err(gettext("be_send_fs_callback: failed to "
2477 2478 "recv dataset (%s)\n"), clone_ds);
2478 2479 }
2479 2480 (void) close(srpipe[0]);
2480 2481
2481 2482 /* wait for child to exit */
2482 2483 do {
2483 2484 retval = waitpid(pid, &status, 0);
2484 2485 if (retval == -1) {
2485 2486 status = 0;
2486 2487 }
2487 2488 } while (retval != pid);
2488 2489
2489 2490 if (WEXITSTATUS(status) != 0) {
2490 2491 be_print_err(gettext("be_send_fs_callback: failed to "
2491 2492 "send dataset (%s)\n"), zhp_name);
2492 2493 ZFS_CLOSE(zhp);
2493 2494 return (BE_ERR_ZFS);
2494 2495 }
2495 2496
2496 2497
2497 2498 /*
2498 2499 * Iterate through zhp's children datasets (if any)
2499 2500 * and send them accordingly.
2500 2501 */
2501 2502 if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2502 2503 /*
2503 2504 * Error occurred while processing a child dataset.
2504 2505 * Destroy this dataset and return error.
2505 2506 */
2506 2507 zfs_handle_t *d_zhp = NULL;
2507 2508
2508 2509 ZFS_CLOSE(zhp);
2509 2510
2510 2511 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2511 2512 == NULL) {
2512 2513 return (ret);
2513 2514 }
2514 2515
2515 2516 (void) zfs_destroy(d_zhp, B_FALSE);
2516 2517 ZFS_CLOSE(d_zhp);
2517 2518 return (ret);
2518 2519 }
2519 2520
2520 2521 ZFS_CLOSE(zhp);
2521 2522 return (0);
2522 2523 }
2523 2524
2524 2525 /*
2525 2526 * Function: be_destroy_callback
2526 2527 * Description: Callback function used to destroy a BEs children datasets
2527 2528 * and snapshots.
2528 2529 * Parameters:
2529 2530 * zhp - zfs_handle_t pointer to the filesystem being processed.
2530 2531 * data - Not used.
2531 2532 * Returns:
2532 2533 * 0 - Success
2533 2534 * be_errno_t - Failure
2534 2535 * Scope:
2535 2536 * Private
2536 2537 */
2537 2538 static int
2538 2539 be_destroy_callback(zfs_handle_t *zhp, void *data)
2539 2540 {
2540 2541 be_destroy_data_t *dd = data;
2541 2542 int ret = 0;
2542 2543
2543 2544 /*
2544 2545 * Iterate down this file system's hierarchical children
2545 2546 * and destroy them first.
2546 2547 */
2547 2548 if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2548 2549 ZFS_CLOSE(zhp);
2549 2550 return (ret);
2550 2551 }
2551 2552
2552 2553 if (dd->destroy_snaps) {
2553 2554 /*
2554 2555 * Iterate through this file system's snapshots and
2555 2556 * destroy them before destroying the file system itself.
2556 2557 */
2557 2558 if ((ret = zfs_iter_snapshots(zhp, B_FALSE, be_destroy_callback,
2558 2559 dd))
2559 2560 != 0) {
2560 2561 ZFS_CLOSE(zhp);
2561 2562 return (ret);
2562 2563 }
2563 2564 }
2564 2565
2565 2566 /* Attempt to unmount the dataset before destroying it */
2566 2567 if (dd->force_unmount) {
2567 2568 if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2568 2569 be_print_err(gettext("be_destroy_callback: "
2569 2570 "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2570 2571 libzfs_error_description(g_zfs));
2571 2572 ret = zfs_err_to_be_err(g_zfs);
2572 2573 ZFS_CLOSE(zhp);
2573 2574 return (ret);
2574 2575 }
2575 2576 }
2576 2577
2577 2578 if (zfs_destroy(zhp, B_FALSE) != 0) {
2578 2579 be_print_err(gettext("be_destroy_callback: "
2579 2580 "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2580 2581 libzfs_error_description(g_zfs));
2581 2582 ret = zfs_err_to_be_err(g_zfs);
2582 2583 ZFS_CLOSE(zhp);
2583 2584 return (ret);
2584 2585 }
2585 2586
2586 2587 ZFS_CLOSE(zhp);
2587 2588 return (0);
2588 2589 }
2589 2590
2590 2591 /*
2591 2592 * Function: be_demote_callback
2592 2593 * Description: This callback function is used to iterate through the file
2593 2594 * systems of a BE, looking for the right clone to promote such
2594 2595 * that this file system is left without any dependent clones.
2595 2596 * If the file system has no dependent clones, it doesn't need
2596 2597 * to get demoted, and the function will return success.
2597 2598 *
2598 2599 * The demotion will be done in two passes. The first pass
2599 2600 * will attempt to find the youngest snapshot that has a clone
2600 2601 * that is part of some other BE. The second pass will attempt
2601 2602 * to find the youngest snapshot that has a clone that is not
2602 2603 * part of a BE. Doing this helps ensure the aggregated set of
2603 2604 * file systems that compose a BE stay coordinated wrt BE
2604 2605 * snapshots and BE dependents. It also prevents a random user
2605 2606 * generated clone of a BE dataset to become the parent of other
2606 2607 * BE datasets after demoting this dataset.
2607 2608 *
2608 2609 * Parameters:
2609 2610 * zhp - zfs_handle_t pointer to the current file system being
2610 2611 * processed.
2611 2612 * data - not used.
2612 2613 * Return:
2613 2614 * 0 - Success
2614 2615 * be_errno_t - Failure
2615 2616 * Scope:
2616 2617 * Private
2617 2618 */
2618 2619 static int
2619 2620 /* LINTED */
2620 2621 be_demote_callback(zfs_handle_t *zhp, void *data)
2621 2622 {
2622 2623 be_demote_data_t dd = { 0 };
2623 2624 int i, ret = 0;
2624 2625
2625 2626 /*
2626 2627 * Initialize be_demote_data for the first pass - this will find a
2627 2628 * clone in another BE, if one exists.
2628 2629 */
2629 2630 dd.find_in_BE = B_TRUE;
2630 2631
2631 2632 for (i = 0; i < 2; i++) {
2632 2633
2633 2634 if (zfs_iter_snapshots(zhp, B_FALSE,
2634 2635 be_demote_find_clone_callback, &dd) != 0) {
2635 2636 be_print_err(gettext("be_demote_callback: "
2636 2637 "failed to iterate snapshots for %s: %s\n"),
2637 2638 zfs_get_name(zhp), libzfs_error_description(g_zfs));
2638 2639 ret = zfs_err_to_be_err(g_zfs);
2639 2640 ZFS_CLOSE(zhp);
2640 2641 return (ret);
2641 2642 }
2642 2643 if (dd.clone_zhp != NULL) {
2643 2644 /* Found the clone to promote. Promote it. */
2644 2645 if (zfs_promote(dd.clone_zhp) != 0) {
2645 2646 be_print_err(gettext("be_demote_callback: "
2646 2647 "failed to promote %s: %s\n"),
2647 2648 zfs_get_name(dd.clone_zhp),
2648 2649 libzfs_error_description(g_zfs));
2649 2650 ret = zfs_err_to_be_err(g_zfs);
2650 2651 ZFS_CLOSE(dd.clone_zhp);
2651 2652 ZFS_CLOSE(zhp);
2652 2653 return (ret);
2653 2654 }
2654 2655
2655 2656 ZFS_CLOSE(dd.clone_zhp);
2656 2657 }
2657 2658
2658 2659 /*
2659 2660 * Reinitialize be_demote_data for the second pass.
2660 2661 * This will find a user created clone outside of any BE
2661 2662 * namespace, if one exists.
2662 2663 */
2663 2664 dd.clone_zhp = NULL;
2664 2665 dd.origin_creation = 0;
2665 2666 dd.snapshot = NULL;
2666 2667 dd.find_in_BE = B_FALSE;
2667 2668 }
2668 2669
2669 2670 /* Iterate down this file system's children and demote them */
2670 2671 if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2671 2672 ZFS_CLOSE(zhp);
2672 2673 return (ret);
2673 2674 }
2674 2675
2675 2676 ZFS_CLOSE(zhp);
2676 2677 return (0);
2677 2678 }
2678 2679
2679 2680 /*
2680 2681 * Function: be_demote_find_clone_callback
2681 2682 * Description: This callback function is used to iterate through the
2682 2683 * snapshots of a dataset, looking for the youngest snapshot
2683 2684 * that has a clone. If found, it returns a reference to the
2684 2685 * clone back to the caller in the callback data.
2685 2686 * Parameters:
2686 2687 * zhp - zfs_handle_t pointer to current snapshot being looked at
2687 2688 * data - be_demote_data_t pointer used to store the clone that
2688 2689 * is found.
2689 2690 * Returns:
2690 2691 * 0 - Successfully iterated through all snapshots.
2691 2692 * 1 - Failed to iterate through all snapshots.
2692 2693 * Scope:
2693 2694 * Private
2694 2695 */
2695 2696 static int
2696 2697 be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2697 2698 {
2698 2699 be_demote_data_t *dd = data;
2699 2700 time_t snap_creation;
2700 2701 int zret = 0;
2701 2702
2702 2703 /* If snapshot has no clones, no need to look at it */
2703 2704 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2704 2705 ZFS_CLOSE(zhp);
2705 2706 return (0);
2706 2707 }
2707 2708
2708 2709 dd->snapshot = zfs_get_name(zhp);
2709 2710
2710 2711 /* Get the creation time of this snapshot */
2711 2712 snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2712 2713
2713 2714 /*
2714 2715 * If this snapshot's creation time is greater than (or younger than)
2715 2716 * the current youngest snapshot found, iterate this snapshot to
2716 2717 * check if it has a clone that we're looking for.
2717 2718 */
2718 2719 if (snap_creation >= dd->origin_creation) {
2719 2720 /*
2720 2721 * Iterate the dependents of this snapshot to find a
2721 2722 * a clone that's a direct dependent.
2722 2723 */
2723 2724 if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2724 2725 be_demote_get_one_clone, dd)) == -1) {
2725 2726 be_print_err(gettext("be_demote_find_clone_callback: "
2726 2727 "failed to iterate dependents of %s\n"),
2727 2728 zfs_get_name(zhp));
2728 2729 ZFS_CLOSE(zhp);
2729 2730 return (1);
2730 2731 } else if (zret == 1) {
2731 2732 /*
2732 2733 * Found a clone, update the origin_creation time
2733 2734 * in the callback data.
2734 2735 */
2735 2736 dd->origin_creation = snap_creation;
2736 2737 }
2737 2738 }
2738 2739
2739 2740 ZFS_CLOSE(zhp);
2740 2741 return (0);
2741 2742 }
2742 2743
2743 2744 /*
2744 2745 * Function: be_demote_get_one_clone
2745 2746 * Description: This callback function is used to iterate through a
2746 2747 * snapshot's dependencies to find a filesystem that is a
2747 2748 * direct clone of the snapshot being iterated.
2748 2749 * Parameters:
2749 2750 * zhp - zfs_handle_t pointer to current dataset being looked at
2750 2751 * data - be_demote_data_t pointer used to store the clone
2751 2752 * that is found, and also provides flag to note
2752 2753 * whether or not the clone filesystem being searched
2753 2754 * for needs to be found in a BE dataset hierarchy.
2754 2755 * Return:
2755 2756 * 1 - Success, found clone and its also a BE's root dataset.
2756 2757 * 0 - Failure, clone not found.
2757 2758 * Scope:
2758 2759 * Private
2759 2760 */
2760 2761 static int
2761 2762 be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2762 2763 {
2763 2764 be_demote_data_t *dd = data;
2764 2765 char origin[ZFS_MAX_DATASET_NAME_LEN];
2765 2766 char ds_path[ZFS_MAX_DATASET_NAME_LEN];
2766 2767
2767 2768 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2768 2769 ZFS_CLOSE(zhp);
2769 2770 return (0);
2770 2771 }
2771 2772
2772 2773 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2773 2774
2774 2775 /*
2775 2776 * Make sure this is a direct clone of the snapshot
2776 2777 * we're iterating.
2777 2778 */
2778 2779 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2779 2780 NULL, 0, B_FALSE) != 0) {
2780 2781 be_print_err(gettext("be_demote_get_one_clone: "
2781 2782 "failed to get origin of %s: %s\n"), ds_path,
2782 2783 libzfs_error_description(g_zfs));
2783 2784 ZFS_CLOSE(zhp);
2784 2785 return (0);
2785 2786 }
2786 2787 if (strcmp(origin, dd->snapshot) != 0) {
2787 2788 ZFS_CLOSE(zhp);
2788 2789 return (0);
2789 2790 }
2790 2791
2791 2792 if (dd->find_in_BE) {
2792 2793 if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2793 2794 > 0) {
2794 2795 if (dd->clone_zhp != NULL)
2795 2796 ZFS_CLOSE(dd->clone_zhp);
2796 2797 dd->clone_zhp = zhp;
2797 2798 return (1);
2798 2799 }
2799 2800
2800 2801 ZFS_CLOSE(zhp);
2801 2802 return (0);
2802 2803 }
2803 2804
2804 2805 if (dd->clone_zhp != NULL)
2805 2806 ZFS_CLOSE(dd->clone_zhp);
2806 2807
2807 2808 dd->clone_zhp = zhp;
2808 2809 return (1);
2809 2810 }
2810 2811
2811 2812 /*
2812 2813 * Function: be_get_snap
2813 2814 * Description: This function takes a snapshot dataset name and separates
2814 2815 * out the parent dataset portion from the snapshot name.
2815 2816 * I.e. it finds the '@' in the snapshot dataset name and
2816 2817 * replaces it with a '\0'.
2817 2818 * Parameters:
2818 2819 * origin - char pointer to a snapshot dataset name. Its
2819 2820 * contents will be modified by this function.
2820 2821 * *snap - pointer to a char pointer. Will be set to the
2821 2822 * snapshot name portion upon success.
2822 2823 * Return:
2823 2824 * BE_SUCCESS - Success
2824 2825 * 1 - Failure
2825 2826 * Scope:
2826 2827 * Private
2827 2828 */
2828 2829 static int
2829 2830 be_get_snap(char *origin, char **snap)
2830 2831 {
2831 2832 char *cp;
2832 2833
2833 2834 /*
2834 2835 * Separate out the origin's dataset and snapshot portions by
2835 2836 * replacing the @ with a '\0'
2836 2837 */
2837 2838 cp = strrchr(origin, '@');
2838 2839 if (cp != NULL) {
2839 2840 if (cp[1] != NULL && cp[1] != '\0') {
2840 2841 cp[0] = '\0';
2841 2842 *snap = cp+1;
2842 2843 } else {
2843 2844 return (1);
2844 2845 }
2845 2846 } else {
2846 2847 return (1);
2847 2848 }
2848 2849
2849 2850 return (BE_SUCCESS);
2850 2851 }
2851 2852
2852 2853 /*
2853 2854 * Function: be_create_container_ds
2854 2855 * Description: This function checks that the zpool passed has the BE
2855 2856 * container dataset, and if not, then creates it.
2856 2857 * Parameters:
2857 2858 * zpool - name of pool to create BE container dataset in.
2858 2859 * Return:
2859 2860 * B_TRUE - Successfully created BE container dataset, or it
2860 2861 * already existed.
2861 2862 * B_FALSE - Failed to create container dataset.
2862 2863 * Scope:
2863 2864 * Private
2864 2865 */
2865 2866 static boolean_t
2866 2867 be_create_container_ds(char *zpool)
2867 2868 {
2868 2869 nvlist_t *props = NULL;
2869 2870 char be_container_ds[MAXPATHLEN];
2870 2871
2871 2872 /* Generate string for BE container dataset for this pool */
2872 2873 be_make_container_ds(zpool, be_container_ds,
2873 2874 sizeof (be_container_ds));
2874 2875
2875 2876 if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2876 2877
2877 2878 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2878 2879 be_print_err(gettext("be_create_container_ds: "
2879 2880 "nvlist_alloc failed\n"));
2880 2881 return (B_FALSE);
2881 2882 }
2882 2883
2883 2884 if (nvlist_add_string(props,
2884 2885 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2885 2886 ZFS_MOUNTPOINT_LEGACY) != 0) {
2886 2887 be_print_err(gettext("be_create_container_ds: "
2887 2888 "internal error: out of memory\n"));
2888 2889 nvlist_free(props);
2889 2890 return (B_FALSE);
2890 2891 }
2891 2892
2892 2893 if (nvlist_add_string(props,
2893 2894 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2894 2895 be_print_err(gettext("be_create_container_ds: "
2895 2896 "internal error: out of memory\n"));
2896 2897 nvlist_free(props);
2897 2898 return (B_FALSE);
2898 2899 }
2899 2900
2900 2901 if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2901 2902 props) != 0) {
2902 2903 be_print_err(gettext("be_create_container_ds: "
2903 2904 "failed to create container dataset (%s): %s\n"),
2904 2905 be_container_ds, libzfs_error_description(g_zfs));
2905 2906 nvlist_free(props);
2906 2907 return (B_FALSE);
2907 2908 }
2908 2909
2909 2910 nvlist_free(props);
2910 2911 }
2911 2912
2912 2913 return (B_TRUE);
2913 2914 }
2914 2915
2915 2916 /*
2916 2917 * Function: be_prep_clone_send_fs
2917 2918 * Description: This function takes a zfs handle to a dataset from the
2918 2919 * original BE, and generates the name of the clone dataset
2919 2920 * to create for the new BE. It also prepares the zfs
2920 2921 * properties to be used for the new BE.
2921 2922 * Parameters:
2922 2923 * zhp - pointer to zfs_handle_t of the file system being
2923 2924 * cloned/copied.
2924 2925 * bt - be_transaction_data pointer providing information
2925 2926 * about the original BE and new BE.
2926 2927 * clone_ds - buffer to store the name of the dataset
2927 2928 * for the new BE.
2928 2929 * clone_ds_len - length of clone_ds buffer
2929 2930 * Return:
2930 2931 * BE_SUCCESS - Success
2931 2932 * be_errno_t - Failure
2932 2933 * Scope:
2933 2934 * Private
2934 2935 */
2935 2936 static int
2936 2937 be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2937 2938 char *clone_ds, int clone_ds_len)
2938 2939 {
2939 2940 zprop_source_t sourcetype;
2940 2941 char source[ZFS_MAX_DATASET_NAME_LEN];
2941 2942 char zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2942 2943 char mountpoint[MAXPATHLEN];
2943 2944 char *child_fs = NULL;
2944 2945 char *zhp_mountpoint = NULL;
2945 2946 int err = 0;
2946 2947
2947 2948 /*
2948 2949 * Get a copy of the dataset name zfs_name from zhp
2949 2950 */
2950 2951 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2951 2952
2952 2953 /*
2953 2954 * Get file system name relative to the root.
2954 2955 */
2955 2956 if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2956 2957 == 0) {
2957 2958 child_fs = zhp_name + strlen(bt->obe_root_ds);
2958 2959
2959 2960 /*
2960 2961 * if child_fs is NULL, this means we're processing the
2961 2962 * root dataset itself; set child_fs to the empty string.
2962 2963 */
2963 2964 if (child_fs == NULL)
2964 2965 child_fs = "";
2965 2966 } else {
2966 2967 return (BE_ERR_INVAL);
2967 2968 }
2968 2969
2969 2970 /*
2970 2971 * Generate the name of the clone file system.
2971 2972 */
2972 2973 (void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2973 2974 child_fs);
2974 2975
2975 2976 /* Get the mountpoint and source properties of the existing dataset */
2976 2977 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2977 2978 sizeof (mountpoint), &sourcetype, source, sizeof (source),
2978 2979 B_FALSE) != 0) {
2979 2980 be_print_err(gettext("be_prep_clone_send_fs: "
2980 2981 "failed to get mountpoint for (%s): %s\n"),
2981 2982 zhp_name, libzfs_error_description(g_zfs));
2982 2983 return (zfs_err_to_be_err(g_zfs));
2983 2984 }
2984 2985
2985 2986 /*
2986 2987 * Workaround for 6668667 where a mountpoint property of "/" comes
2987 2988 * back as "".
2988 2989 */
2989 2990 if (strcmp(mountpoint, "") == 0) {
2990 2991 (void) snprintf(mountpoint, sizeof (mountpoint), "/");
2991 2992 }
2992 2993
2993 2994 /*
2994 2995 * Figure out what to set as the mountpoint for the new dataset.
2995 2996 * If the source of the mountpoint property is local, use the
2996 2997 * mountpoint value itself. Otherwise, remove it from the
2997 2998 * zfs properties list so that it gets inherited.
2998 2999 */
2999 3000 if (sourcetype & ZPROP_SRC_LOCAL) {
3000 3001 /*
3001 3002 * If the BE that this file system is a part of is
3002 3003 * currently mounted, strip off the BE altroot portion
3003 3004 * from the mountpoint.
3004 3005 */
3005 3006 zhp_mountpoint = mountpoint;
3006 3007
3007 3008 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
3008 3009 bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
3009 3010 "/") != 0 && zfs_is_mounted(zhp, NULL)) {
3010 3011
3011 3012 int altroot_len = strlen(bt->obe_altroot);
3012 3013
3013 3014 if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
3014 3015 == 0) {
3015 3016 if (mountpoint[altroot_len] == '/')
3016 3017 zhp_mountpoint = mountpoint +
3017 3018 altroot_len;
3018 3019 else if (mountpoint[altroot_len] == '\0')
3019 3020 (void) snprintf(mountpoint,
3020 3021 sizeof (mountpoint), "/");
3021 3022 }
3022 3023 }
3023 3024
3024 3025 if (nvlist_add_string(bt->nbe_zfs_props,
3025 3026 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
3026 3027 zhp_mountpoint) != 0) {
3027 3028 be_print_err(gettext("be_prep_clone_send_fs: "
3028 3029 "internal error: out of memory\n"));
3029 3030 return (BE_ERR_NOMEM);
3030 3031 }
3031 3032 } else {
3032 3033 err = nvlist_remove_all(bt->nbe_zfs_props,
3033 3034 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
3034 3035 if (err != 0 && err != ENOENT) {
3035 3036 be_print_err(gettext("be_prep_clone_send_fs: "
3036 3037 "failed to remove mountpoint from "
3037 3038 "nvlist\n"));
3038 3039 return (BE_ERR_INVAL);
3039 3040 }
3040 3041 }
3041 3042
3042 3043 /*
3043 3044 * Set the 'canmount' property
3044 3045 */
3045 3046 if (nvlist_add_string(bt->nbe_zfs_props,
3046 3047 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
3047 3048 be_print_err(gettext("be_prep_clone_send_fs: "
3048 3049 "internal error: out of memory\n"));
3049 3050 return (BE_ERR_NOMEM);
3050 3051 }
3051 3052
3052 3053 return (BE_SUCCESS);
3053 3054 }
3054 3055
3055 3056 /*
3056 3057 * Function: be_get_zone_be_name
3057 3058 * Description: This function takes the zones root dataset, the container
3058 3059 * dataset and returns the zones BE name based on the zone
3059 3060 * root dataset.
3060 3061 * Parameters:
3061 3062 * root_ds - the zones root dataset.
3062 3063 * container_ds - the container dataset for the zone.
3063 3064 * Returns:
3064 3065 * char * - the BE name of this zone based on the root dataset.
3065 3066 */
3066 3067 static char *
3067 3068 be_get_zone_be_name(char *root_ds, char *container_ds)
3068 3069 {
3069 3070 return (root_ds + (strlen(container_ds) + 1));
3070 3071 }
3071 3072
3072 3073 /*
3073 3074 * Function: be_zone_root_exists_callback
3074 3075 * Description: This callback function is used to determine if a
3075 3076 * zone root container dataset has any children. It always
3076 3077 * returns 1, signifying a hierarchical child of the zone
3077 3078 * root container dataset has been traversed and therefore
3078 3079 * it has children.
3079 3080 * Parameters:
3080 3081 * zhp - zfs_handle_t pointer to current dataset being processed.
3081 3082 * data - not used.
3082 3083 * Returns:
3083 3084 * 1 - dataset exists
3084 3085 * Scope:
3085 3086 * Private
3086 3087 */
3087 3088 static int
3088 3089 /* LINTED */
3089 3090 be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
3090 3091 {
3091 3092 ZFS_CLOSE(zhp);
3092 3093 return (1);
3093 3094 }
|
↓ open down ↓ |
608 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX