1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * System includes
28 */
29 #include <assert.h>
30 #include <libintl.h>
31 #include <libnvpair.h>
32 #include <libzfs.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39
40 #include <libbe.h>
41 #include <libbe_priv.h>
42
43 /* Private function prototypes */
44 static int be_rollback_check_callback(zfs_handle_t *, void *);
45 static int be_rollback_callback(zfs_handle_t *, void *);
46
47
48 /* ******************************************************************** */
49 /* Public Functions */
50 /* ******************************************************************** */
51
52 /*
53 * Function: be_create_snapshot
54 * Description: Creates a recursive snapshot of all the datasets within a BE.
55 * If the name of the BE to snapshot is not provided, it assumes
56 * we're snapshotting the currently running BE. If the snapshot
57 * name is not provided it creates an auto named snapshot, which
58 * will be returned to the caller upon success.
59 * Parameters:
60 * be_attrs - pointer to nvlist_t of attributes being passed in.
61 * The following attributes are used by this function:
62 *
63 * BE_ATTR_ORIG_BE_NAME *optional
64 * BE_ATTR_SNAP_NAME *optional
65 * BE_ATTR_POLICY *optional
66 *
67 * If the BE_ATTR_SNAP_NAME was not passed in, upon
68 * successful BE snapshot creation, the following
69 * attribute value will be returned to the caller by
70 * setting it in the be_attrs parameter passed in:
71 *
72 * BE_ATTR_SNAP_NAME
73 *
74 * Return:
75 * BE_SUCCESS - Success
76 * be_errno_t - Failure
77 * Scope:
78 * Public
79 */
80 int
be_create_snapshot(nvlist_t * be_attrs)81 be_create_snapshot(nvlist_t *be_attrs)
82 {
83 char *be_name = NULL;
84 char *snap_name = NULL;
85 char *policy = NULL;
86 boolean_t autoname = B_FALSE;
87 int ret = BE_SUCCESS;
88
89 /* Initialize libzfs handle */
90 if (!be_zfs_init())
91 return (BE_ERR_INIT);
92
93 /* Get original BE name if one was provided */
94 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
95 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) {
96 be_print_err(gettext("be_create_snapshot: failed to "
97 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
98 be_zfs_fini();
99 return (BE_ERR_INVAL);
100 }
101
102 /* Validate original BE name if one was provided */
103 if (be_name != NULL && !be_valid_be_name(be_name)) {
104 be_print_err(gettext("be_create_snapshot: "
105 "invalid BE name %s\n"), be_name);
106 be_zfs_fini();
107 return (BE_ERR_INVAL);
108 }
109
110 /* Get snapshot name to create if one was provided */
111 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
112 BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &snap_name, NULL) != 0) {
113 be_print_err(gettext("be_create_snapshot: "
114 "failed to lookup BE_ATTR_SNAP_NAME attribute\n"));
115 be_zfs_fini();
116 return (BE_ERR_INVAL);
117 }
118
119 /* Get BE policy to create this snapshot under */
120 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
121 BE_ATTR_POLICY, DATA_TYPE_STRING, &policy, NULL) != 0) {
122 be_print_err(gettext("be_create_snapshot: "
123 "failed to lookup BE_ATTR_POLICY attribute\n"));
124 be_zfs_fini();
125 return (BE_ERR_INVAL);
126 }
127
128 /*
129 * If no snap_name ws provided, we're going to create an
130 * auto named snapshot. Set flag so that we know to pass
131 * the auto named snapshot to the caller later.
132 */
133 if (snap_name == NULL)
134 autoname = B_TRUE;
135
136 if ((ret = _be_create_snapshot(be_name, &snap_name, policy))
137 == BE_SUCCESS) {
138 if (autoname == B_TRUE) {
139 /*
140 * Set auto named snapshot name in the
141 * nvlist passed in by the caller.
142 */
143 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
144 snap_name) != 0) {
145 be_print_err(gettext("be_create_snapshot: "
146 "failed to add auto snap name (%s) to "
147 "be_attrs\n"), snap_name);
148 ret = BE_ERR_NOMEM;
149 }
150 }
151 }
152
153 be_zfs_fini();
154
155 return (ret);
156 }
157
158 /*
159 * Function: be_destroy_snapshot
160 * Description: Iterates through all the datasets of the BE and deletes
161 * the snapshots of each one with the specified name. If the
162 * BE name is not provided, it assumes we're operating on the
163 * currently running BE. The name of the snapshot name to
164 * destroy must be provided.
165 * Parameters:
166 * be_attrs - pointer to nvlist_t of attributes being passed in.
167 * The following attribute values are used by this
168 * function:
169 *
170 * BE_ATTR_ORIG_BE_NAME *optional
171 * BE_ATTR_SNAP_NAME *required
172 * Return:
173 * BE_SUCCESS - Success
174 * be_errno_t - Failure
175 * Scope:
176 * Public
177 */
178 int
be_destroy_snapshot(nvlist_t * be_attrs)179 be_destroy_snapshot(nvlist_t *be_attrs)
180 {
181 char *be_name = NULL;
182 char *snap_name = NULL;
183 int ret = BE_SUCCESS;
184
185 /* Initialize libzfs handle */
186 if (!be_zfs_init())
187 return (BE_ERR_INIT);
188
189 /* Get original BE name if one was provided */
190 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
191 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) {
192 be_print_err(gettext("be_destroy_snapshot: "
193 "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
194 return (BE_ERR_INVAL);
195 }
196
197 /* Validate original BE name if one was provided */
198 if (be_name != NULL && !be_valid_be_name(be_name)) {
199 be_print_err(gettext("be_destroy_snapshot: "
200 "invalid BE name %s\n"), be_name);
201 return (BE_ERR_INVAL);
202 }
203
204 /* Get snapshot name to destroy */
205 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &snap_name)
206 != 0) {
207 be_print_err(gettext("be_destroy_snapshot: "
208 "failed to lookup BE_ATTR_SNAP_NAME attribute.\n"));
209 return (BE_ERR_INVAL);
210 }
211
212 ret = _be_destroy_snapshot(be_name, snap_name);
213
214 be_zfs_fini();
215
216 return (ret);
217 }
218
219 /*
220 * Function: be_rollback
221 * Description: Rolls back a BE and all of its children datasets to the
222 * named snapshot. All of the BE's datasets must have the
223 * named snapshot for this function to succeed. If the name
224 * of the BE is not passed in, this function assumes we're
225 * operating on the currently booted live BE.
226 *
227 * Note - This function does not check if the BE has any
228 * younger snapshots than the one we're trying to rollback to.
229 * If it does, then those younger snapshots and their dependent
230 * clone file systems will get destroyed in the process of
231 * rolling back.
232 *
233 * Parameters:
234 * be_attrs - pointer to nvlist_t of attributes being passed in.
235 * The following attributes are used by this function:
236 *
237 * BE_ATTR_ORIG_BE_NAME *optional
238 * BE_ATTR_SNAP_NAME *required
239 *
240 * Returns:
241 * BE_SUCCESS - Success
242 * be_errno_t - Failure
243 * Scope:
244 * Public
245 */
246 int
be_rollback(nvlist_t * be_attrs)247 be_rollback(nvlist_t *be_attrs)
248 {
249 be_transaction_data_t bt = { 0 };
250 zfs_handle_t *zhp = NULL;
251 char obe_root_ds[MAXPATHLEN];
252 int zret = 0, ret = BE_SUCCESS;
253
254 /* Initialize libzfs handle */
255 if (!be_zfs_init())
256 return (BE_ERR_INIT);
257
258 /* Get original BE name if one was provided */
259 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
260 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) {
261 be_print_err(gettext("be_rollback: "
262 "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
263 return (BE_ERR_INVAL);
264 }
265
266 /* If original BE name not provided, use current BE */
267 if (bt.obe_name == NULL) {
268 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
269 return (ret);
270 }
271 } else {
272 /* Validate original BE name */
273 if (!be_valid_be_name(bt.obe_name)) {
274 be_print_err(gettext("be_rollback: "
275 "invalid BE name %s\n"), bt.obe_name);
276 return (BE_ERR_INVAL);
277 }
278 }
279
280 /* Get snapshot name to rollback to */
281 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &bt.obe_snap_name)
282 != 0) {
283 be_print_err(gettext("be_rollback: "
284 "failed to lookup BE_ATTR_SNAP_NAME attribute.\n"));
285 return (BE_ERR_INVAL);
286 }
287
288 /* Find which zpool obe_name lives in */
289 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
290 be_print_err(gettext("be_rollback: "
291 "failed to find zpool for BE (%s)\n"), bt.obe_name);
292 return (BE_ERR_BE_NOENT);
293 } else if (zret < 0) {
294 be_print_err(gettext("be_rollback: "
295 "zpool_iter failed: %s\n"),
296 libzfs_error_description(g_zfs));
297 return (zfs_err_to_be_err(g_zfs));
298 }
299
300 /* Generate string for BE's root dataset */
301 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
302 sizeof (obe_root_ds));
303 bt.obe_root_ds = obe_root_ds;
304
305 /* Get handle to BE's root dataset */
306 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) {
307 be_print_err(gettext("be_rollback: "
308 "failed to open BE root dataset (%s): %s\n"),
309 bt.obe_root_ds, libzfs_error_description(g_zfs));
310 return (zfs_err_to_be_err(g_zfs));
311 }
312
313 /*
314 * Check that snapshot name exists for this BE and all of its
315 * children file systems. This call will end up closing the
316 * zfs handle passed in whether it succeeds or fails.
317 */
318 if ((ret = be_rollback_check_callback(zhp, bt.obe_snap_name)) != 0) {
319 zhp = NULL;
320 return (ret);
321 }
322
323 /* Get handle to BE's root dataset */
324 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) {
325 be_print_err(gettext("be_rollback: "
326 "failed to open BE root dataset (%s): %s\n"),
327 bt.obe_root_ds, libzfs_error_description(g_zfs));
328 return (zfs_err_to_be_err(g_zfs));
329 }
330
331 /*
332 * Iterate through a BE's datasets and roll them all back to
333 * the specified snapshot. This call will end up closing the
334 * zfs handle passed in whether it succeeds or fails.
335 */
336 if ((ret = be_rollback_callback(zhp, bt.obe_snap_name)) != 0) {
337 zhp = NULL;
338 be_print_err(gettext("be_rollback: "
339 "failed to rollback BE %s to %s\n"), bt.obe_name,
340 bt.obe_snap_name);
341 return (ret);
342 }
343 zhp = NULL;
344 be_zfs_fini();
345 return (BE_SUCCESS);
346 }
347
348
349 /* ******************************************************************** */
350 /* Semi-Private Functions */
351 /* ******************************************************************** */
352
353 /*
354 * Function: _be_create_snapshot
355 * Description: see be_create_snapshot
356 * Parameters:
357 * be_name - The name of the BE that we're taking a snapshot of.
358 * snap_name - The name of the snapshot we're creating. If
359 * snap_name is NULL an auto generated name will be used,
360 * and upon success, will return that name via this
361 * reference pointer. The caller is responsible for
362 * freeing the returned name.
363 * policy - The clean-up policy type. (library wide use only)
364 * Return:
365 * BE_SUCCESS - Success
366 * be_errno_t - Failure
367 * Scope:
368 * Semi-private (library wide use only)
369 */
370 int
_be_create_snapshot(char * be_name,char ** snap_name,char * policy)371 _be_create_snapshot(char *be_name, char **snap_name, char *policy)
372 {
373 be_transaction_data_t bt = { 0 };
374 zfs_handle_t *zhp = NULL;
375 nvlist_t *ss_props = NULL;
376 char ss[MAXPATHLEN];
377 char root_ds[MAXPATHLEN];
378 int pool_version = 0;
379 int i = 0;
380 int zret = 0, ret = BE_SUCCESS;
381 boolean_t autoname = B_FALSE;
382
383 /* Set parameters in bt structure */
384 bt.obe_name = be_name;
385 bt.obe_snap_name = *snap_name;
386 bt.policy = policy;
387
388 /* If original BE name not supplied, use current BE */
389 if (bt.obe_name == NULL) {
390 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
391 return (ret);
392 }
393 }
394
395 /* Find which zpool obe_name lives in */
396 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
397 be_print_err(gettext("be_create_snapshot: failed to "
398 "find zpool for BE (%s)\n"), bt.obe_name);
399 return (BE_ERR_BE_NOENT);
400 } else if (zret < 0) {
401 be_print_err(gettext("be_create_snapshot: "
402 "zpool_iter failed: %s\n"),
403 libzfs_error_description(g_zfs));
404 return (zfs_err_to_be_err(g_zfs));
405 }
406
407 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds,
408 sizeof (root_ds));
409 bt.obe_root_ds = root_ds;
410
411 /* If BE policy not specified, use the default policy */
412 if (bt.policy == NULL) {
413 bt.policy = be_default_policy();
414 } else {
415 /* Validate policy type */
416 if (!valid_be_policy(bt.policy)) {
417 be_print_err(gettext("be_create_snapshot: "
418 "invalid BE policy type (%s)\n"), bt.policy);
419 return (BE_ERR_INVAL);
420 }
421 }
422
423 /*
424 * If snapshot name not specified, set auto name flag and
425 * generate auto snapshot name.
426 */
427 if (bt.obe_snap_name == NULL) {
428 autoname = B_TRUE;
429 if ((bt.obe_snap_name = be_auto_snap_name())
430 == NULL) {
431 be_print_err(gettext("be_create_snapshot: "
432 "failed to create auto snapshot name\n"));
433 ret = BE_ERR_AUTONAME;
434 goto done;
435 }
436 }
437
438 /* Generate the name of the snapshot to take. */
439 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
440 bt.obe_snap_name);
441
442 /* Get handle to BE's root dataset */
443 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET))
444 == NULL) {
445 be_print_err(gettext("be_create_snapshot: "
446 "failed to open BE root dataset (%s): %s\n"),
447 bt.obe_root_ds, libzfs_error_description(g_zfs));
448 ret = zfs_err_to_be_err(g_zfs);
449 goto done;
450 }
451
452 /* Get the ZFS pool version of the pool where this dataset resides */
453 if (zfs_spa_version(zhp, &pool_version) != 0) {
454 be_print_err(gettext("be_create_snapshot: failed to "
455 "get ZFS pool version for %s: %s\n"), zfs_get_name(zhp),
456 libzfs_error_description(g_zfs));
457 }
458
459 /*
460 * If ZFS pool version supports snapshot user properties, store
461 * cleanup policy there. Otherwise don't set one - this snapshot
462 * will always inherit the cleanup policy from its parent.
463 */
464 if (pool_version >= SPA_VERSION_SNAP_PROPS) {
465 if (nvlist_alloc(&ss_props, NV_UNIQUE_NAME, 0) != 0) {
466 be_print_err(gettext("be_create_snapshot: internal "
467 "error: out of memory\n"));
468 return (BE_ERR_NOMEM);
469 }
470 if (nvlist_add_string(ss_props, BE_POLICY_PROPERTY, bt.policy)
471 != 0) {
472 be_print_err(gettext("be_create_snapshot: internal "
473 "error: out of memory\n"));
474 nvlist_free(ss_props);
475 return (BE_ERR_NOMEM);
476 }
477 } else if (policy != NULL) {
478 /*
479 * If an explicit cleanup policy was requested
480 * by the caller and we don't support it, error out.
481 */
482 be_print_err(gettext("be_create_snapshot: cannot set "
483 "cleanup policy: ZFS pool version is %d\n"), pool_version);
484 return (BE_ERR_NOTSUP);
485 }
486
487 /* Create the snapshots recursively */
488 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) != 0) {
489 if (!autoname || libzfs_errno(g_zfs) != EZFS_EXISTS) {
490 be_print_err(gettext("be_create_snapshot: "
491 "recursive snapshot of %s failed: %s\n"),
492 ss, libzfs_error_description(g_zfs));
493
494 if (libzfs_errno(g_zfs) == EZFS_EXISTS)
495 ret = BE_ERR_SS_EXISTS;
496 else
497 ret = zfs_err_to_be_err(g_zfs);
498
499 goto done;
500 } else {
501 for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
502
503 /* Sleep 1 before retrying */
504 (void) sleep(1);
505
506 /* Generate new auto snapshot name. */
507 free(bt.obe_snap_name);
508 if ((bt.obe_snap_name =
509 be_auto_snap_name()) == NULL) {
510 be_print_err(gettext(
511 "be_create_snapshot: failed to "
512 "create auto snapshot name\n"));
513 ret = BE_ERR_AUTONAME;
514 goto done;
515 }
516
517 /* Generate string of the snapshot to take. */
518 (void) snprintf(ss, sizeof (ss), "%s@%s",
519 bt.obe_root_ds, bt.obe_snap_name);
520
521 /* Create the snapshots recursively */
522 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props)
523 != 0) {
524 if (libzfs_errno(g_zfs) !=
525 EZFS_EXISTS) {
526 be_print_err(gettext(
527 "be_create_snapshot: "
528 "recursive snapshot of %s "
529 "failed: %s\n"), ss,
530 libzfs_error_description(
531 g_zfs));
532 ret = zfs_err_to_be_err(g_zfs);
533 goto done;
534 }
535 } else {
536 break;
537 }
538 }
539
540 /*
541 * If we exhausted the maximum number of tries,
542 * free the auto snap name and set error.
543 */
544 if (i == BE_AUTO_NAME_MAX_TRY) {
545 be_print_err(gettext("be_create_snapshot: "
546 "failed to create unique auto snapshot "
547 "name\n"));
548 free(bt.obe_snap_name);
549 bt.obe_snap_name = NULL;
550 ret = BE_ERR_AUTONAME;
551 }
552 }
553 }
554
555 /*
556 * If we succeeded in creating an auto named snapshot, store
557 * the name in the nvlist passed in by the caller.
558 */
559 if (autoname && bt.obe_snap_name) {
560 *snap_name = bt.obe_snap_name;
561 }
562
563 done:
564 ZFS_CLOSE(zhp);
565
566 if (ss_props != NULL)
567 nvlist_free(ss_props);
568
569 return (ret);
570 }
571
572 /*
573 * Function: _be_destroy_snapshot
574 * Description: see be_destroy_snapshot
575 * Parameters:
576 * be_name - The name of the BE that the snapshot belongs to.
577 * snap_name - The name of the snapshot we're destroying.
578 * Return:
579 * BE_SUCCESS - Success
580 * be_errno_t - Failure
581 * Scope:
582 * Semi-private (library wide use only)
583 */
584 int
_be_destroy_snapshot(char * be_name,char * snap_name)585 _be_destroy_snapshot(char *be_name, char *snap_name)
586 {
587 be_transaction_data_t bt = { 0 };
588 zfs_handle_t *zhp;
589 char ss[MAXPATHLEN];
590 char root_ds[MAXPATHLEN];
591 int err = BE_SUCCESS, ret = BE_SUCCESS;
592
593 /* Make sure we actaully have a snapshot name */
594 if (snap_name == NULL) {
595 be_print_err(gettext("be_destroy_snapshot: "
596 "invalid snapshot name\n"));
597 return (BE_ERR_INVAL);
598 }
599
600 /* Set parameters in bt structure */
601 bt.obe_name = be_name;
602 bt.obe_snap_name = snap_name;
603
604 /* If original BE name not supplied, use current BE */
605 if (bt.obe_name == NULL) {
606 if ((err = be_find_current_be(&bt)) != BE_SUCCESS) {
607 return (err);
608 }
609 }
610
611 /* Find which zpool be_name lives in */
612 if ((ret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
613 be_print_err(gettext("be_destroy_snapshot: "
614 "failed to find zpool for BE (%s)\n"), bt.obe_name);
615 return (BE_ERR_BE_NOENT);
616 } else if (ret < 0) {
617 be_print_err(gettext("be_destroy_snapshot: "
618 "zpool_iter failed: %s\n"),
619 libzfs_error_description(g_zfs));
620 return (zfs_err_to_be_err(g_zfs));
621 }
622
623 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds,
624 sizeof (root_ds));
625 bt.obe_root_ds = root_ds;
626
627 zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET);
628 if (zhp == NULL) {
629 /*
630 * The zfs_open failed, return an error.
631 */
632 be_print_err(gettext("be_destroy_snapshot: "
633 "failed to open BE root dataset (%s): %s\n"),
634 bt.obe_root_ds, libzfs_error_description(g_zfs));
635 err = zfs_err_to_be_err(g_zfs);
636 } else {
637 /*
638 * Generate the name of the snapshot to take.
639 */
640 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_name,
641 bt.obe_snap_name);
642
643 /*
644 * destroy the snapshot.
645 */
646 /*
647 * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
648 * tells zfs to process and destroy the snapshots now.
649 * Otherwise the call will potentially return where the
650 * snapshot isn't actually destroyed yet, and ZFS is waiting
651 * until all the references to the snapshot have been
652 * released before actually destroying the snapshot.
653 */
654 if (zfs_destroy_snaps(zhp, bt.obe_snap_name, B_FALSE) != 0) {
655 err = zfs_err_to_be_err(g_zfs);
656 be_print_err(gettext("be_destroy_snapshot: "
657 "failed to destroy snapshot %s: %s\n"), ss,
658 libzfs_error_description(g_zfs));
659 }
660 }
661
662 ZFS_CLOSE(zhp);
663
664 return (err);
665 }
666
667 /* ******************************************************************** */
668 /* Private Functions */
669 /* ******************************************************************** */
670
671 /*
672 * Function: be_rollback_check_callback
673 * Description: Callback function used to iterate through a BE's filesystems
674 * to check if a given snapshot name exists.
675 * Parameters:
676 * zhp - zfs_handle_t pointer to filesystem being processed.
677 * data - name of the snapshot to check for.
678 * Returns:
679 * 0 - Success, snapshot name exists for all filesystems.
680 * be_errno_t - Failure, snapshot name does not exist for all
681 * filesystems.
682 * Scope:
683 * Private
684 */
685 static int
be_rollback_check_callback(zfs_handle_t * zhp,void * data)686 be_rollback_check_callback(zfs_handle_t *zhp, void *data)
687 {
688 char *snap_name = data;
689 char ss[MAXPATHLEN];
690 int ret = BE_SUCCESS;
691
692 /* Generate string for this filesystem's snapshot name */
693 (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name);
694
695 /* Check if snapshot exists */
696 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
697 be_print_err(gettext("be_rollback_check_callback: "
698 "snapshot does not exist %s\n"), ss);
699 ZFS_CLOSE(zhp);
700 return (BE_ERR_SS_NOENT);
701 }
702
703 /* Iterate this dataset's children and check them */
704 if ((ret = zfs_iter_filesystems(zhp, be_rollback_check_callback,
705 snap_name)) != 0) {
706 ZFS_CLOSE(zhp);
707 return (ret);
708 }
709
710 ZFS_CLOSE(zhp);
711 return (0);
712 }
713
714 /*
715 * Function: be_rollback_callback
716 * Description: Callback function used to iterate through a BE's filesystems
717 * and roll them all back to the specified snapshot name.
718 * Parameters:
719 * zhp - zfs_handle_t pointer to filesystem being processed.
720 * data - name of snapshot to rollback to.
721 * Returns:
722 * 0 - Success
723 * be_errno_t - Failure
724 * Scope:
725 * Private
726 */
727 static int
be_rollback_callback(zfs_handle_t * zhp,void * data)728 be_rollback_callback(zfs_handle_t *zhp, void *data)
729 {
730 zfs_handle_t *zhp_snap = NULL;
731 char *snap_name = data;
732 char ss[MAXPATHLEN];
733 int ret = 0;
734
735 /* Generate string for this filesystem's snapshot name */
736 (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name);
737
738 /* Get handle to this filesystem's snapshot */
739 if ((zhp_snap = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
740 be_print_err(gettext("be_rollback_callback: "
741 "failed to open snapshot %s: %s\n"), zfs_get_name(zhp),
742 libzfs_error_description(g_zfs));
743 ret = zfs_err_to_be_err(g_zfs);
744 ZFS_CLOSE(zhp);
745 return (ret);
746 }
747
748 /* Rollback dataset */
749 if (zfs_rollback(zhp, zhp_snap, B_FALSE) != 0) {
750 be_print_err(gettext("be_rollback_callback: "
751 "failed to rollback BE dataset %s to snapshot %s: %s\n"),
752 zfs_get_name(zhp), ss, libzfs_error_description(g_zfs));
753 ret = zfs_err_to_be_err(g_zfs);
754 ZFS_CLOSE(zhp_snap);
755 ZFS_CLOSE(zhp);
756 return (ret);
757 }
758
759 ZFS_CLOSE(zhp_snap);
760 /* Iterate this dataset's children and roll them back */
761 if ((ret = zfs_iter_filesystems(zhp, be_rollback_callback,
762 snap_name)) != 0) {
763 ZFS_CLOSE(zhp);
764 return (ret);
765 }
766
767 ZFS_CLOSE(zhp);
768 return (0);
769 }
770