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