719 beadm should allow BEs outside of <rpool>/ROOT
[unleashed.git] / usr / src / lib / libbe / common / be_snapshot.c
blob2cb011ea5a72f3843734e7f5021217d1a13ce787
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
31 * System includes
33 #include <assert.h>
34 #include <libintl.h>
35 #include <libnvpair.h>
36 #include <libzfs.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
44 #include <libbe.h>
45 #include <libbe_priv.h>
47 /* Private function prototypes */
48 static int be_rollback_check_callback(zfs_handle_t *, void *);
49 static int be_rollback_callback(zfs_handle_t *, void *);
52 /* ******************************************************************** */
53 /* Public Functions */
54 /* ******************************************************************** */
57 * Function: be_create_snapshot
58 * Description: Creates a recursive snapshot of all the datasets within a BE.
59 * If the name of the BE to snapshot is not provided, it assumes
60 * we're snapshotting the currently running BE. If the snapshot
61 * name is not provided it creates an auto named snapshot, which
62 * will be returned to the caller upon success.
63 * Parameters:
64 * be_attrs - pointer to nvlist_t of attributes being passed in.
65 * The following attributes are used by this function:
67 * BE_ATTR_ORIG_BE_NAME *optional
68 * BE_ATTR_SNAP_NAME *optional
69 * BE_ATTR_POLICY *optional
71 * If the BE_ATTR_SNAP_NAME was not passed in, upon
72 * successful BE snapshot creation, the following
73 * attribute value will be returned to the caller by
74 * setting it in the be_attrs parameter passed in:
76 * BE_ATTR_SNAP_NAME
78 * Return:
79 * BE_SUCCESS - Success
80 * be_errno_t - Failure
81 * Scope:
82 * Public
84 int
85 be_create_snapshot(nvlist_t *be_attrs)
87 char *be_name = NULL;
88 char *snap_name = NULL;
89 char *policy = NULL;
90 boolean_t autoname = B_FALSE;
91 int ret = BE_SUCCESS;
93 /* Initialize libzfs handle */
94 if (!be_zfs_init())
95 return (BE_ERR_INIT);
97 /* Get original BE name if one was provided */
98 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
99 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) {
100 be_print_err(gettext("be_create_snapshot: failed to "
101 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
102 be_zfs_fini();
103 return (BE_ERR_INVAL);
106 /* Validate original BE name if one was provided */
107 if (be_name != NULL && !be_valid_be_name(be_name)) {
108 be_print_err(gettext("be_create_snapshot: "
109 "invalid BE name %s\n"), be_name);
110 be_zfs_fini();
111 return (BE_ERR_INVAL);
114 /* Get snapshot name to create if one was provided */
115 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
116 BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &snap_name, NULL) != 0) {
117 be_print_err(gettext("be_create_snapshot: "
118 "failed to lookup BE_ATTR_SNAP_NAME attribute\n"));
119 be_zfs_fini();
120 return (BE_ERR_INVAL);
123 /* Get BE policy to create this snapshot under */
124 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
125 BE_ATTR_POLICY, DATA_TYPE_STRING, &policy, NULL) != 0) {
126 be_print_err(gettext("be_create_snapshot: "
127 "failed to lookup BE_ATTR_POLICY attribute\n"));
128 be_zfs_fini();
129 return (BE_ERR_INVAL);
133 * If no snap_name ws provided, we're going to create an
134 * auto named snapshot. Set flag so that we know to pass
135 * the auto named snapshot to the caller later.
137 if (snap_name == NULL)
138 autoname = B_TRUE;
140 if ((ret = _be_create_snapshot(be_name, &snap_name, policy))
141 == BE_SUCCESS) {
142 if (autoname == B_TRUE) {
144 * Set auto named snapshot name in the
145 * nvlist passed in by the caller.
147 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
148 snap_name) != 0) {
149 be_print_err(gettext("be_create_snapshot: "
150 "failed to add auto snap name (%s) to "
151 "be_attrs\n"), snap_name);
152 ret = BE_ERR_NOMEM;
157 be_zfs_fini();
159 return (ret);
163 * Function: be_destroy_snapshot
164 * Description: Iterates through all the datasets of the BE and deletes
165 * the snapshots of each one with the specified name. If the
166 * BE name is not provided, it assumes we're operating on the
167 * currently running BE. The name of the snapshot name to
168 * destroy must be provided.
169 * Parameters:
170 * be_attrs - pointer to nvlist_t of attributes being passed in.
171 * The following attribute values are used by this
172 * function:
174 * BE_ATTR_ORIG_BE_NAME *optional
175 * BE_ATTR_SNAP_NAME *required
176 * Return:
177 * BE_SUCCESS - Success
178 * be_errno_t - Failure
179 * Scope:
180 * Public
183 be_destroy_snapshot(nvlist_t *be_attrs)
185 char *be_name = NULL;
186 char *snap_name = NULL;
187 int ret = BE_SUCCESS;
189 /* Initialize libzfs handle */
190 if (!be_zfs_init())
191 return (BE_ERR_INIT);
193 /* Get original BE name if one was provided */
194 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
195 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) {
196 be_print_err(gettext("be_destroy_snapshot: "
197 "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
198 return (BE_ERR_INVAL);
201 /* Validate original BE name if one was provided */
202 if (be_name != NULL && !be_valid_be_name(be_name)) {
203 be_print_err(gettext("be_destroy_snapshot: "
204 "invalid BE name %s\n"), be_name);
205 return (BE_ERR_INVAL);
208 /* Get snapshot name to destroy */
209 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &snap_name)
210 != 0) {
211 be_print_err(gettext("be_destroy_snapshot: "
212 "failed to lookup BE_ATTR_SNAP_NAME attribute.\n"));
213 return (BE_ERR_INVAL);
216 ret = _be_destroy_snapshot(be_name, snap_name);
218 be_zfs_fini();
220 return (ret);
224 * Function: be_rollback
225 * Description: Rolls back a BE and all of its children datasets to the
226 * named snapshot. All of the BE's datasets must have the
227 * named snapshot for this function to succeed. If the name
228 * of the BE is not passed in, this function assumes we're
229 * operating on the currently booted live BE.
231 * Note - This function does not check if the BE has any
232 * younger snapshots than the one we're trying to rollback to.
233 * If it does, then those younger snapshots and their dependent
234 * clone file systems will get destroyed in the process of
235 * rolling back.
237 * Parameters:
238 * be_attrs - pointer to nvlist_t of attributes being passed in.
239 * The following attributes are used by this function:
241 * BE_ATTR_ORIG_BE_NAME *optional
242 * BE_ATTR_SNAP_NAME *required
244 * Returns:
245 * BE_SUCCESS - Success
246 * be_errno_t - Failure
247 * Scope:
248 * Public
251 be_rollback(nvlist_t *be_attrs)
253 be_transaction_data_t bt = { 0 };
254 zfs_handle_t *zhp = NULL;
255 zpool_handle_t *zphp;
256 char obe_root_ds[MAXPATHLEN];
257 char *obe_name = NULL;
258 int zret = 0, ret = BE_SUCCESS;
259 struct be_defaults be_defaults;
261 /* Initialize libzfs handle */
262 if (!be_zfs_init())
263 return (BE_ERR_INIT);
265 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
266 return (ret);
269 /* Get original BE name if one was provided */
270 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
271 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
272 be_print_err(gettext("be_rollback: "
273 "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
274 return (BE_ERR_INVAL);
277 be_get_defaults(&be_defaults);
279 /* If original BE name not provided, use current BE */
280 if (obe_name != NULL) {
281 bt.obe_name = obe_name;
282 /* Validate original BE name */
283 if (!be_valid_be_name(bt.obe_name)) {
284 be_print_err(gettext("be_rollback: "
285 "invalid BE name %s\n"), bt.obe_name);
286 return (BE_ERR_INVAL);
290 /* Get snapshot name to rollback to */
291 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &bt.obe_snap_name)
292 != 0) {
293 be_print_err(gettext("be_rollback: "
294 "failed to lookup BE_ATTR_SNAP_NAME attribute.\n"));
295 return (BE_ERR_INVAL);
298 if (be_defaults.be_deflt_rpool_container) {
299 if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
300 be_print_err(gettext("be_rollback: failed to "
301 "open rpool (%s): %s\n"), bt.obe_zpool,
302 libzfs_error_description(g_zfs));
303 return (zfs_err_to_be_err(g_zfs));
305 zret = be_find_zpool_callback(zphp, &bt);
306 } else {
307 /* Find which zpool obe_name lives in */
308 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
309 0) {
310 be_print_err(gettext("be_rollback: "
311 "failed to find zpool for BE (%s)\n"), bt.obe_name);
312 return (BE_ERR_BE_NOENT);
313 } else if (zret < 0) {
314 be_print_err(gettext("be_rollback: "
315 "zpool_iter failed: %s\n"),
316 libzfs_error_description(g_zfs));
317 return (zfs_err_to_be_err(g_zfs));
321 /* Generate string for BE's root dataset */
322 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
323 sizeof (obe_root_ds));
324 bt.obe_root_ds = obe_root_ds;
326 /* Get handle to BE's root dataset */
327 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) {
328 be_print_err(gettext("be_rollback: "
329 "failed to open BE root dataset (%s): %s\n"),
330 bt.obe_root_ds, libzfs_error_description(g_zfs));
331 return (zfs_err_to_be_err(g_zfs));
335 * Check that snapshot name exists for this BE and all of its
336 * children file systems. This call will end up closing the
337 * zfs handle passed in whether it succeeds or fails.
339 if ((ret = be_rollback_check_callback(zhp, bt.obe_snap_name)) != 0) {
340 zhp = NULL;
341 return (ret);
344 /* Get handle to BE's root dataset */
345 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) {
346 be_print_err(gettext("be_rollback: "
347 "failed to open BE root dataset (%s): %s\n"),
348 bt.obe_root_ds, libzfs_error_description(g_zfs));
349 return (zfs_err_to_be_err(g_zfs));
353 * Iterate through a BE's datasets and roll them all back to
354 * the specified snapshot. This call will end up closing the
355 * zfs handle passed in whether it succeeds or fails.
357 if ((ret = be_rollback_callback(zhp, bt.obe_snap_name)) != 0) {
358 zhp = NULL;
359 be_print_err(gettext("be_rollback: "
360 "failed to rollback BE %s to %s\n"), bt.obe_name,
361 bt.obe_snap_name);
362 return (ret);
364 zhp = NULL;
365 be_zfs_fini();
366 return (BE_SUCCESS);
370 /* ******************************************************************** */
371 /* Semi-Private Functions */
372 /* ******************************************************************** */
375 * Function: _be_create_snapshot
376 * Description: see be_create_snapshot
377 * Parameters:
378 * be_name - The name of the BE that we're taking a snapshot of.
379 * snap_name - The name of the snapshot we're creating. If
380 * snap_name is NULL an auto generated name will be used,
381 * and upon success, will return that name via this
382 * reference pointer. The caller is responsible for
383 * freeing the returned name.
384 * policy - The clean-up policy type. (library wide use only)
385 * Return:
386 * BE_SUCCESS - Success
387 * be_errno_t - Failure
388 * Scope:
389 * Semi-private (library wide use only)
392 _be_create_snapshot(char *be_name, char **snap_name, char *policy)
394 be_transaction_data_t bt = { 0 };
395 zfs_handle_t *zhp = NULL;
396 nvlist_t *ss_props = NULL;
397 char ss[MAXPATHLEN];
398 char root_ds[MAXPATHLEN];
399 int pool_version = 0;
400 int i = 0;
401 int zret = 0, ret = BE_SUCCESS;
402 boolean_t autoname = B_FALSE;
404 /* Set parameters in bt structure */
405 bt.obe_name = be_name;
406 bt.obe_snap_name = *snap_name;
407 bt.policy = policy;
409 /* If original BE name not supplied, use current BE */
410 if (bt.obe_name == NULL) {
411 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
412 return (ret);
416 /* Find which zpool obe_name lives in */
417 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
418 be_print_err(gettext("be_create_snapshot: failed to "
419 "find zpool for BE (%s)\n"), bt.obe_name);
420 return (BE_ERR_BE_NOENT);
421 } else if (zret < 0) {
422 be_print_err(gettext("be_create_snapshot: "
423 "zpool_iter failed: %s\n"),
424 libzfs_error_description(g_zfs));
425 return (zfs_err_to_be_err(g_zfs));
428 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds,
429 sizeof (root_ds));
430 bt.obe_root_ds = root_ds;
432 /* If BE policy not specified, use the default policy */
433 if (bt.policy == NULL) {
434 bt.policy = be_default_policy();
435 } else {
436 /* Validate policy type */
437 if (!valid_be_policy(bt.policy)) {
438 be_print_err(gettext("be_create_snapshot: "
439 "invalid BE policy type (%s)\n"), bt.policy);
440 return (BE_ERR_INVAL);
445 * If snapshot name not specified, set auto name flag and
446 * generate auto snapshot name.
448 if (bt.obe_snap_name == NULL) {
449 autoname = B_TRUE;
450 if ((bt.obe_snap_name = be_auto_snap_name())
451 == NULL) {
452 be_print_err(gettext("be_create_snapshot: "
453 "failed to create auto snapshot name\n"));
454 ret = BE_ERR_AUTONAME;
455 goto done;
459 /* Generate the name of the snapshot to take. */
460 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
461 bt.obe_snap_name);
463 /* Get handle to BE's root dataset */
464 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET))
465 == NULL) {
466 be_print_err(gettext("be_create_snapshot: "
467 "failed to open BE root dataset (%s): %s\n"),
468 bt.obe_root_ds, libzfs_error_description(g_zfs));
469 ret = zfs_err_to_be_err(g_zfs);
470 goto done;
473 /* Get the ZFS pool version of the pool where this dataset resides */
474 if (zfs_spa_version(zhp, &pool_version) != 0) {
475 be_print_err(gettext("be_create_snapshot: failed to "
476 "get ZFS pool version for %s: %s\n"), zfs_get_name(zhp),
477 libzfs_error_description(g_zfs));
481 * If ZFS pool version supports snapshot user properties, store
482 * cleanup policy there. Otherwise don't set one - this snapshot
483 * will always inherit the cleanup policy from its parent.
485 if (pool_version >= SPA_VERSION_SNAP_PROPS) {
486 if (nvlist_alloc(&ss_props, NV_UNIQUE_NAME, 0) != 0) {
487 be_print_err(gettext("be_create_snapshot: internal "
488 "error: out of memory\n"));
489 return (BE_ERR_NOMEM);
491 if (nvlist_add_string(ss_props, BE_POLICY_PROPERTY, bt.policy)
492 != 0) {
493 be_print_err(gettext("be_create_snapshot: internal "
494 "error: out of memory\n"));
495 nvlist_free(ss_props);
496 return (BE_ERR_NOMEM);
498 } else if (policy != NULL) {
500 * If an explicit cleanup policy was requested
501 * by the caller and we don't support it, error out.
503 be_print_err(gettext("be_create_snapshot: cannot set "
504 "cleanup policy: ZFS pool version is %d\n"), pool_version);
505 return (BE_ERR_NOTSUP);
508 /* Create the snapshots recursively */
509 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) != 0) {
510 if (!autoname || libzfs_errno(g_zfs) != EZFS_EXISTS) {
511 be_print_err(gettext("be_create_snapshot: "
512 "recursive snapshot of %s failed: %s\n"),
513 ss, libzfs_error_description(g_zfs));
515 if (libzfs_errno(g_zfs) == EZFS_EXISTS)
516 ret = BE_ERR_SS_EXISTS;
517 else
518 ret = zfs_err_to_be_err(g_zfs);
520 goto done;
521 } else {
522 for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
524 /* Sleep 1 before retrying */
525 (void) sleep(1);
527 /* Generate new auto snapshot name. */
528 free(bt.obe_snap_name);
529 if ((bt.obe_snap_name =
530 be_auto_snap_name()) == NULL) {
531 be_print_err(gettext(
532 "be_create_snapshot: failed to "
533 "create auto snapshot name\n"));
534 ret = BE_ERR_AUTONAME;
535 goto done;
538 /* Generate string of the snapshot to take. */
539 (void) snprintf(ss, sizeof (ss), "%s@%s",
540 bt.obe_root_ds, bt.obe_snap_name);
542 /* Create the snapshots recursively */
543 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props)
544 != 0) {
545 if (libzfs_errno(g_zfs) !=
546 EZFS_EXISTS) {
547 be_print_err(gettext(
548 "be_create_snapshot: "
549 "recursive snapshot of %s "
550 "failed: %s\n"), ss,
551 libzfs_error_description(
552 g_zfs));
553 ret = zfs_err_to_be_err(g_zfs);
554 goto done;
556 } else {
557 break;
562 * If we exhausted the maximum number of tries,
563 * free the auto snap name and set error.
565 if (i == BE_AUTO_NAME_MAX_TRY) {
566 be_print_err(gettext("be_create_snapshot: "
567 "failed to create unique auto snapshot "
568 "name\n"));
569 free(bt.obe_snap_name);
570 bt.obe_snap_name = NULL;
571 ret = BE_ERR_AUTONAME;
577 * If we succeeded in creating an auto named snapshot, store
578 * the name in the nvlist passed in by the caller.
580 if (autoname && bt.obe_snap_name) {
581 *snap_name = bt.obe_snap_name;
584 done:
585 ZFS_CLOSE(zhp);
587 if (ss_props != NULL)
588 nvlist_free(ss_props);
590 return (ret);
594 * Function: _be_destroy_snapshot
595 * Description: see be_destroy_snapshot
596 * Parameters:
597 * be_name - The name of the BE that the snapshot belongs to.
598 * snap_name - The name of the snapshot we're destroying.
599 * Return:
600 * BE_SUCCESS - Success
601 * be_errno_t - Failure
602 * Scope:
603 * Semi-private (library wide use only)
606 _be_destroy_snapshot(char *be_name, char *snap_name)
608 be_transaction_data_t bt = { 0 };
609 zfs_handle_t *zhp;
610 char ss[MAXPATHLEN];
611 char root_ds[MAXPATHLEN];
612 int err = BE_SUCCESS, ret = BE_SUCCESS;
614 /* Make sure we actaully have a snapshot name */
615 if (snap_name == NULL) {
616 be_print_err(gettext("be_destroy_snapshot: "
617 "invalid snapshot name\n"));
618 return (BE_ERR_INVAL);
621 /* Set parameters in bt structure */
622 bt.obe_name = be_name;
623 bt.obe_snap_name = snap_name;
625 /* If original BE name not supplied, use current BE */
626 if (bt.obe_name == NULL) {
627 if ((err = be_find_current_be(&bt)) != BE_SUCCESS) {
628 return (err);
632 /* Find which zpool be_name lives in */
633 if ((ret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
634 be_print_err(gettext("be_destroy_snapshot: "
635 "failed to find zpool for BE (%s)\n"), bt.obe_name);
636 return (BE_ERR_BE_NOENT);
637 } else if (ret < 0) {
638 be_print_err(gettext("be_destroy_snapshot: "
639 "zpool_iter failed: %s\n"),
640 libzfs_error_description(g_zfs));
641 return (zfs_err_to_be_err(g_zfs));
644 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds,
645 sizeof (root_ds));
646 bt.obe_root_ds = root_ds;
648 zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET);
649 if (zhp == NULL) {
651 * The zfs_open failed, return an error.
653 be_print_err(gettext("be_destroy_snapshot: "
654 "failed to open BE root dataset (%s): %s\n"),
655 bt.obe_root_ds, libzfs_error_description(g_zfs));
656 err = zfs_err_to_be_err(g_zfs);
657 } else {
659 * Generate the name of the snapshot to take.
661 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_name,
662 bt.obe_snap_name);
665 * destroy the snapshot.
668 * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
669 * tells zfs to process and destroy the snapshots now.
670 * Otherwise the call will potentially return where the
671 * snapshot isn't actually destroyed yet, and ZFS is waiting
672 * until all the references to the snapshot have been
673 * released before actually destroying the snapshot.
675 if (zfs_destroy_snaps(zhp, bt.obe_snap_name, B_FALSE) != 0) {
676 err = zfs_err_to_be_err(g_zfs);
677 be_print_err(gettext("be_destroy_snapshot: "
678 "failed to destroy snapshot %s: %s\n"), ss,
679 libzfs_error_description(g_zfs));
683 ZFS_CLOSE(zhp);
685 return (err);
688 /* ******************************************************************** */
689 /* Private Functions */
690 /* ******************************************************************** */
693 * Function: be_rollback_check_callback
694 * Description: Callback function used to iterate through a BE's filesystems
695 * to check if a given snapshot name exists.
696 * Parameters:
697 * zhp - zfs_handle_t pointer to filesystem being processed.
698 * data - name of the snapshot to check for.
699 * Returns:
700 * 0 - Success, snapshot name exists for all filesystems.
701 * be_errno_t - Failure, snapshot name does not exist for all
702 * filesystems.
703 * Scope:
704 * Private
706 static int
707 be_rollback_check_callback(zfs_handle_t *zhp, void *data)
709 char *snap_name = data;
710 char ss[MAXPATHLEN];
711 int ret = BE_SUCCESS;
713 /* Generate string for this filesystem's snapshot name */
714 (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name);
716 /* Check if snapshot exists */
717 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
718 be_print_err(gettext("be_rollback_check_callback: "
719 "snapshot does not exist %s\n"), ss);
720 ZFS_CLOSE(zhp);
721 return (BE_ERR_SS_NOENT);
724 /* Iterate this dataset's children and check them */
725 if ((ret = zfs_iter_filesystems(zhp, be_rollback_check_callback,
726 snap_name)) != 0) {
727 ZFS_CLOSE(zhp);
728 return (ret);
731 ZFS_CLOSE(zhp);
732 return (0);
736 * Function: be_rollback_callback
737 * Description: Callback function used to iterate through a BE's filesystems
738 * and roll them all back to the specified snapshot name.
739 * Parameters:
740 * zhp - zfs_handle_t pointer to filesystem being processed.
741 * data - name of snapshot to rollback to.
742 * Returns:
743 * 0 - Success
744 * be_errno_t - Failure
745 * Scope:
746 * Private
748 static int
749 be_rollback_callback(zfs_handle_t *zhp, void *data)
751 zfs_handle_t *zhp_snap = NULL;
752 char *snap_name = data;
753 char ss[MAXPATHLEN];
754 int ret = 0;
756 /* Generate string for this filesystem's snapshot name */
757 (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name);
759 /* Get handle to this filesystem's snapshot */
760 if ((zhp_snap = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
761 be_print_err(gettext("be_rollback_callback: "
762 "failed to open snapshot %s: %s\n"), zfs_get_name(zhp),
763 libzfs_error_description(g_zfs));
764 ret = zfs_err_to_be_err(g_zfs);
765 ZFS_CLOSE(zhp);
766 return (ret);
769 /* Rollback dataset */
770 if (zfs_rollback(zhp, zhp_snap, B_FALSE) != 0) {
771 be_print_err(gettext("be_rollback_callback: "
772 "failed to rollback BE dataset %s to snapshot %s: %s\n"),
773 zfs_get_name(zhp), ss, libzfs_error_description(g_zfs));
774 ret = zfs_err_to_be_err(g_zfs);
775 ZFS_CLOSE(zhp_snap);
776 ZFS_CLOSE(zhp);
777 return (ret);
780 ZFS_CLOSE(zhp_snap);
781 /* Iterate this dataset's children and roll them back */
782 if ((ret = zfs_iter_filesystems(zhp, be_rollback_callback,
783 snap_name)) != 0) {
784 ZFS_CLOSE(zhp);
785 return (ret);
788 ZFS_CLOSE(zhp);
789 return (0);