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