Print this page
*** NO COMMENTS ***


   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  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  28  */
  29 
  30 /*
  31  * System includes
  32  */
  33 
  34 #include <assert.h>
  35 #include <ctype.h>
  36 #include <errno.h>
  37 #include <libgen.h>
  38 #include <libintl.h>
  39 #include <libnvpair.h>
  40 #include <libzfs.h>
  41 #include <stdio.h>
  42 #include <stdlib.h>
  43 #include <string.h>
  44 #include <sys/mnttab.h>
  45 #include <sys/mount.h>
  46 #include <sys/stat.h>
  47 #include <sys/types.h>


 433 
 434         dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
 435         dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
 436 
 437         /* Find which zpool obe_name lives in */
 438         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 439                 be_print_err(gettext("be_destroy: failed to find zpool "
 440                     "for BE (%s)\n"), bt.obe_name);
 441                 return (BE_ERR_BE_NOENT);
 442         } else if (zret < 0) {
 443                 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
 444                     libzfs_error_description(g_zfs));
 445                 return (zfs_err_to_be_err(g_zfs));
 446         }
 447 
 448         /* Generate string for obe_name's root dataset */
 449         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 450             sizeof (obe_root_ds));
 451         bt.obe_root_ds = obe_root_ds;
 452 











 453         /*
 454          * Detect if the BE to destroy has the 'active on boot' property set.
 455          * If so, set the 'active on boot' property on the the 'active' BE.
 456          */
 457         if (be_is_active_on_boot(bt.obe_name)) {
 458                 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
 459                         be_print_err(gettext("be_destroy: failed to "
 460                             "make the current BE 'active on boot'\n"));
 461                         return (ret);
 462                 }
 463         }
 464 
 465         /* Get handle to BE's root dataset */
 466         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 467             NULL) {
 468                 be_print_err(gettext("be_destroy: failed to "
 469                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 470                     libzfs_error_description(g_zfs));
 471                 return (zfs_err_to_be_err(g_zfs));
 472         }
 473 
 474         /*
 475          * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
 476          * is not set.
 477          */
 478         (void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
 479         if (!dd.destroy_snaps && bs_found) {
 480                 ZFS_CLOSE(zhp);
 481                 return (BE_ERR_SS_EXISTS);
 482         }
 483 
 484         /* 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));


 488         }

 489 
 490         /*
 491          * If the global BE is mounted, make sure we've been given the
 492          * flag to forcibly unmount it.
 493          */
 494         if (zfs_is_mounted(zhp, &mp)) {
 495                 if (!(dd.force_unmount)) {
 496                         be_print_err(gettext("be_destroy: "
 497                             "%s is currently mounted at %s, cannot destroy\n"),
 498                             bt.obe_name, mp != NULL ? mp : "<unknown>");
 499 
 500                         free(mp);
 501                         ZFS_CLOSE(zhp);
 502                         return (BE_ERR_MOUNTED);
 503                 }
 504                 free(mp);
 505         }
 506 
 507         /*
 508          * Destroy the non-global zone BE's if we are in the global zone


 578  *                      will be returned to the caller by setting them in the
 579  *                      be_attrs parameter passed in:
 580  *
 581  *                      BE_ATTR_SNAP_NAME
 582  *                      BE_ATTR_NEW_BE_NAME
 583  * Return:
 584  *              BE_SUCCESS - Success
 585  *              be_errno_t - Failure
 586  * Scope:
 587  *              Public
 588  */
 589 int
 590 be_copy(nvlist_t *be_attrs)
 591 {
 592         be_transaction_data_t   bt = { 0 };
 593         be_fs_list_data_t       fld = { 0 };
 594         zfs_handle_t    *zhp = NULL;
 595         zpool_handle_t  *zphp = NULL;
 596         nvlist_t        *zfs_props = NULL;
 597         uuid_t          uu = { 0 };

 598         char            obe_root_ds[MAXPATHLEN];
 599         char            nbe_root_ds[MAXPATHLEN];
 600         char            ss[MAXPATHLEN];
 601         char            *new_mp = NULL;
 602         char            *obe_name = NULL;
 603         boolean_t       autoname = B_FALSE;
 604         boolean_t       be_created = B_FALSE;
 605         int             i;
 606         int             zret;
 607         int             ret = BE_SUCCESS;
 608         struct be_defaults be_defaults;
 609 
 610         /* Initialize libzfs handle */
 611         if (!be_zfs_init())
 612                 return (BE_ERR_INIT);
 613 
 614         /* Get original BE name */
 615         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 616             BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
 617                 be_print_err(gettext("be_copy: failed to lookup "


 736                         be_print_err(gettext("be_copy: internal "
 737                             "error: out of memory\n"));
 738                         return (BE_ERR_NOMEM);
 739                 }
 740         }
 741 
 742         /*
 743          * If new BE name provided, validate the BE name and then verify
 744          * that new BE name doesn't already exist in some pool.
 745          */
 746         if (bt.nbe_name) {
 747                 /* Validate original BE name */
 748                 if (!be_valid_be_name(bt.nbe_name)) {
 749                         be_print_err(gettext("be_copy: "
 750                             "invalid BE name %s\n"), bt.nbe_name);
 751                         ret = BE_ERR_INVAL;
 752                         goto done;
 753                 }
 754 
 755                 /* 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;
 767                 }
 768         } else {











 769                 /*
 770                  * If an auto named BE is desired, it must be in the same
 771                  * pool is the original BE.
 772                  */
 773                 if (bt.nbe_zpool != NULL) {
 774                         be_print_err(gettext("be_copy: cannot specify pool "
 775                             "name when creating an auto named BE\n"));
 776                         ret = BE_ERR_INVAL;
 777                         goto done;
 778                 }
 779 
 780                 /*
 781                  * Generate auto named BE
 782                  */
 783                 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
 784                     == NULL) {
 785                         be_print_err(gettext("be_copy: "
 786                             "failed to generate auto BE name\n"));
 787                         ret = BE_ERR_AUTONAME;
 788                         goto done;


 999          * Set flag to note that the dataset(s) for the new BE have been
1000          * successfully created so that if a failure happens from this point
1001          * on, we know to cleanup these datasets.
1002          */
1003         be_created = B_TRUE;
1004 
1005         /*
1006          * Validate that the new BE is mountable.
1007          * Do not attempt to mount non-global zone datasets
1008          * since they are not cloned yet.
1009          */
1010         if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1011             != BE_SUCCESS) {
1012                 be_print_err(gettext("be_copy: failed to "
1013                     "mount newly created BE\n"));
1014                 (void) _be_unmount(bt.nbe_name, 0);
1015                 goto done;
1016         }
1017 
1018         /* 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"));
1022         }














1023 
1024         /*
1025          * Process zones outside of the private BE namespace.
1026          * This has to be done here because we need the uuid set in the
1027          * root dataset of the new BE. The uuid is use to set the parentbe
1028          * property for the new zones datasets.
1029          */
1030         if (getzoneid() == GLOBAL_ZONEID &&
1031             be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1032                 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1033                     bt.nbe_root_ds)) != BE_SUCCESS) {
1034                         be_print_err(gettext("be_copy: failed to process "
1035                             "zones\n"));
1036                         goto done;
1037                 }
1038         }
1039 
1040         /*
1041          * Generate a list of file systems from the original BE that are
1042          * legacy mounted.  We use this list to determine which entries in




   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  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  28  */
  29 
  30 /*
  31  * System includes
  32  */
  33 
  34 #include <assert.h>
  35 #include <ctype.h>
  36 #include <errno.h>
  37 #include <libgen.h>
  38 #include <libintl.h>
  39 #include <libnvpair.h>
  40 #include <libzfs.h>
  41 #include <stdio.h>
  42 #include <stdlib.h>
  43 #include <string.h>
  44 #include <sys/mnttab.h>
  45 #include <sys/mount.h>
  46 #include <sys/stat.h>
  47 #include <sys/types.h>


 433 
 434         dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
 435         dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
 436 
 437         /* Find which zpool obe_name lives in */
 438         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 439                 be_print_err(gettext("be_destroy: failed to find zpool "
 440                     "for BE (%s)\n"), bt.obe_name);
 441                 return (BE_ERR_BE_NOENT);
 442         } else if (zret < 0) {
 443                 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
 444                     libzfs_error_description(g_zfs));
 445                 return (zfs_err_to_be_err(g_zfs));
 446         }
 447 
 448         /* Generate string for obe_name's root dataset */
 449         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 450             sizeof (obe_root_ds));
 451         bt.obe_root_ds = obe_root_ds;
 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 
 464         /*
 465          * Detect if the BE to destroy has the 'active on boot' property set.
 466          * If so, set the 'active on boot' property on the the 'active' BE.
 467          */
 468         if (be_is_active_on_boot(bt.obe_name)) {
 469                 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
 470                         be_print_err(gettext("be_destroy: failed to "
 471                             "make the current BE 'active on boot'\n"));
 472                         return (ret);
 473                 }
 474         }
 475 
 476         /* Get handle to BE's root dataset */
 477         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 478             NULL) {
 479                 be_print_err(gettext("be_destroy: failed to "
 480                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 481                     libzfs_error_description(g_zfs));
 482                 return (zfs_err_to_be_err(g_zfs));
 483         }
 484 
 485         /*
 486          * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
 487          * is not set.
 488          */
 489         (void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
 490         if (!dd.destroy_snaps && bs_found) {
 491                 ZFS_CLOSE(zhp);
 492                 return (BE_ERR_SS_EXISTS);
 493         }
 494 
 495         /* Get the UUID of the global BE */
 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                 }
 502         }
 503 
 504         /*
 505          * If the global BE is mounted, make sure we've been given the
 506          * flag to forcibly unmount it.
 507          */
 508         if (zfs_is_mounted(zhp, &mp)) {
 509                 if (!(dd.force_unmount)) {
 510                         be_print_err(gettext("be_destroy: "
 511                             "%s is currently mounted at %s, cannot destroy\n"),
 512                             bt.obe_name, mp != NULL ? mp : "<unknown>");
 513 
 514                         free(mp);
 515                         ZFS_CLOSE(zhp);
 516                         return (BE_ERR_MOUNTED);
 517                 }
 518                 free(mp);
 519         }
 520 
 521         /*
 522          * Destroy the non-global zone BE's if we are in the global zone


 592  *                      will be returned to the caller by setting them in the
 593  *                      be_attrs parameter passed in:
 594  *
 595  *                      BE_ATTR_SNAP_NAME
 596  *                      BE_ATTR_NEW_BE_NAME
 597  * Return:
 598  *              BE_SUCCESS - Success
 599  *              be_errno_t - Failure
 600  * Scope:
 601  *              Public
 602  */
 603 int
 604 be_copy(nvlist_t *be_attrs)
 605 {
 606         be_transaction_data_t   bt = { 0 };
 607         be_fs_list_data_t       fld = { 0 };
 608         zfs_handle_t    *zhp = NULL;
 609         zpool_handle_t  *zphp = NULL;
 610         nvlist_t        *zfs_props = NULL;
 611         uuid_t          uu = { 0 };
 612         uuid_t          parent_uu = { 0 };
 613         char            obe_root_ds[MAXPATHLEN];
 614         char            nbe_root_ds[MAXPATHLEN];
 615         char            ss[MAXPATHLEN];
 616         char            *new_mp = NULL;
 617         char            *obe_name = NULL;
 618         boolean_t       autoname = B_FALSE;
 619         boolean_t       be_created = B_FALSE;
 620         int             i;
 621         int             zret;
 622         int             ret = BE_SUCCESS;
 623         struct be_defaults be_defaults;
 624 
 625         /* Initialize libzfs handle */
 626         if (!be_zfs_init())
 627                 return (BE_ERR_INIT);
 628 
 629         /* Get original BE name */
 630         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 631             BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
 632                 be_print_err(gettext("be_copy: failed to lookup "


 751                         be_print_err(gettext("be_copy: internal "
 752                             "error: out of memory\n"));
 753                         return (BE_ERR_NOMEM);
 754                 }
 755         }
 756 
 757         /*
 758          * If new BE name provided, validate the BE name and then verify
 759          * that new BE name doesn't already exist in some pool.
 760          */
 761         if (bt.nbe_name) {
 762                 /* Validate original BE name */
 763                 if (!be_valid_be_name(bt.nbe_name)) {
 764                         be_print_err(gettext("be_copy: "
 765                             "invalid BE name %s\n"), bt.nbe_name);
 766                         ret = BE_ERR_INVAL;
 767                         goto done;
 768                 }
 769 
 770                 /* Verify it doesn't already exist */
 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                         }
 795                 }
 796         } else {
 797                 /*
 798                  * If an auto named BE is desired, it must be in the same
 799                  * pool is the original BE.
 800                  */
 801                 if (bt.nbe_zpool != NULL) {
 802                         be_print_err(gettext("be_copy: cannot specify pool "
 803                             "name when creating an auto named BE\n"));
 804                         ret = BE_ERR_INVAL;
 805                         goto done;
 806                 }
 807 
 808                 /*
 809                  * Generate auto named BE
 810                  */
 811                 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
 812                     == NULL) {
 813                         be_print_err(gettext("be_copy: "
 814                             "failed to generate auto BE name\n"));
 815                         ret = BE_ERR_AUTONAME;
 816                         goto done;


1027          * Set flag to note that the dataset(s) for the new BE have been
1028          * successfully created so that if a failure happens from this point
1029          * on, we know to cleanup these datasets.
1030          */
1031         be_created = B_TRUE;
1032 
1033         /*
1034          * Validate that the new BE is mountable.
1035          * Do not attempt to mount non-global zone datasets
1036          * since they are not cloned yet.
1037          */
1038         if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1039             != BE_SUCCESS) {
1040                 be_print_err(gettext("be_copy: failed to "
1041                     "mount newly created BE\n"));
1042                 (void) _be_unmount(bt.nbe_name, 0);
1043                 goto done;
1044         }
1045 
1046         /* Set UUID for new BE */
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                 }
1065         }
1066 
1067         /*
1068          * Process zones outside of the private BE namespace.
1069          * This has to be done here because we need the uuid set in the
1070          * root dataset of the new BE. The uuid is use to set the parentbe
1071          * property for the new zones datasets.
1072          */
1073         if (getzoneid() == GLOBAL_ZONEID &&
1074             be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1075                 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1076                     bt.nbe_root_ds)) != BE_SUCCESS) {
1077                         be_print_err(gettext("be_copy: failed to process "
1078                             "zones\n"));
1079                         goto done;
1080                 }
1081         }
1082 
1083         /*
1084          * Generate a list of file systems from the original BE that are
1085          * legacy mounted.  We use this list to determine which entries in