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