2N/A# The contents of this file are subject to the terms of the 2N/A# Common Development and Distribution License (the "License"). 2N/A# You may not use this file except in compliance with the License. 2N/A# See the License for the specific language governing permissions 2N/A# and limitations under the License. 2N/A# When distributing Covered Code, include this CDDL HEADER in each 2N/A# If applicable, add the following below this CDDL HEADER, with the 2N/A# fields enclosed by brackets "[]" replaced with your own identifying 2N/A# information: Portions Copyright [yyyy] [name of copyright owner] 2N/A# Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 2N/A# get script name (bname) 2N/A # first figure out if the target fs has an origin snapshot 2N/A if [[ $? != 0 ]]; then 2N/A # note that we specify the '-r' flag so that we destroy any 2N/A # descendants (filesystems and snapshot) of the specified 2N/A if [[ $? != 0 ]]; then 2N/A # we ignore errors while trying to destroy the origin since 2N/A # the origin could have been used as the source for other 2N/A if [[ $? != 0 ]]; then 2N/A if [[ $? != 0 ]]; then 2N/A if [[ $? != 0 ]]; then 2N/A # Fastpath. if there are no snapshots of $fs then just delete it. 2N/A if (( $c == 0 )); then 2N/A # This zone BE has snapshots. This can happen if a zone has 2N/A # multiple BEs (in which case we have snapshots named "zbe-XXX"), 2N/A # if this zone has been used as the source for a clone of 2N/A # another zone (in which case we have snapshots named 2N/A # "XXX_snap"), or if an administrator has been doing manual 2N/A # To be able to destroy this dataset (which we'll call the 2N/A # origin) we need to get rid of all it's snapshots. The "easiest" 2N/A # way to do this is to: 2N/A # - delete any uncloned origin snapshots 2N/A # - find the oldest clone of the youngest origin snapshot (which 2N/A # we'll call the oldest clone) 2N/A # - check if there are any snapshots naming conflicts between 2N/A # the origin and the oldest clone. 2N/A # - if so, find any clones of those conflicting origin snapshots 2N/A # - make sure that those clones are not zoned an in-use. 2N/A # - if any of those clones are zoned, unzone them. 2N/A # - rename origin snapshots to eliminate naming conflicts 2N/A # - for any clones that we unzoned, rezone them. 2N/A # - promote the oldest clone 2N/A # - destroy the origin and all it's descendants 2N/A # Get a list of all the cloned datasets within the zpool 2N/A # containing the origin filesystem. Filter out any filesystems 2N/A # that are descendants of origin because we are planning to 2N/A # destroy them anyway. 2N/A # skip non-clone filesystems 2N/A # skip desendents of the origin we plan to destroy 2N/A # record this clone and it's origin 2N/A # Now do a sanity check. Search for clones of a child datasets 2N/A # of the dataset we want to destroy, that are not themselves 2N/A # children of the dataset we're going to destroy). This should 2N/A # really never happen unless the global zone admin has cloned a 2N/A # snapshot of a zone filesystem to a location outside of that 2N/A # zone. bad admin... 2N/A # is the clone origin a descendant of $fs? 2N/A if [[ "${clones_origin[$j]}" != ~()(${fs}/*) ]]; then 2N/A # sigh. the admin has done something strange. 2N/A # tell them to clean it up and retry. 2N/A # Find all the snapshots of the origin filesystem. 2N/A # Now go through the origin snapshots and find those which don't 2N/A # have clones. We're going to explicity delete these snapshots 2N/A # before we do the promotion. 2N/A # if we have a match then break out of this loop 2N/A [[ "${s_origin[$j]}" == "${clones_origin[$k]}" ]] && 2N/A # this snapshot has a clone, move on to the next one 2N/A # snapshot has no clones so add it to our delete list 2N/A # remove it from the origin snapshot list 2N/A # Fastpath. If there are no remaining snapshots then just 2N/A # delete the origin filesystem (and all it's descendents) and 2N/A # move onto the next zone BE. 2N/A # find the youngest snapshot of $fs 2N/A # Find the oldest clone of the youngest snapshot of $fs 2N/A while (( $j >= 0 )); do 2N/A # uh oh. something has gone wrong. bail. 2N/A # create an array of clone snapshot names 2N/A # create an arrays of possible origin snapshot renames 2N/A # Search for snapshot name collisions between the origin and 2N/A # oldest clone. If we find one, generate a new name for the 2N/A # origin snapshot and re-do the collision check. 2N/A # if there's no naming conflict continue 2N/A if [[ "${s_rename[$j]}" != "${s_clone_s[$k]}" ]]; then 2N/A # The origin snapshot conflicts with a clone 2N/A # snapshot. Choose a new name and then restart 2N/A # then check that against clone snapshot names. 2N/A # if we didn't rename this snapshot then continue 2N/A if [[ "${s_rename[$j]}" == "${s_origin_snap[$j]}" ]]; then 2N/A # We need to rename this origin snapshot because it 2N/A # conflicts with a clone snapshot name. So above we 2N/A # chose a name that didn't conflict with any other clone 2N/A # snapshot names. But we also have to avoid naming 2N/A # conflicts with any other origin snapshot names. So 2N/A # check for that now. 2N/A # don't compare against ourself 2N/A if (( $j == $k )); then 2N/A # if there's no naming conflict continue 2N/A if [[ "${s_rename[$j]}" != "${s_rename[$k]}" ]]; then 2N/A # The new origin snapshot name conflicts with 2N/A # another origin snapshot name. Choose a new 2N/A # name and then go back to check the new name 2N/A # for uniqueness against all the clone snapshot 2N/A # A new unique name has been chosen. Move on to the 2N/A # next origin snapshot. 2N/A # So now we know what snapshots need to be renamed before the 2N/A # promotion. But there's an additional problem. If any of the 2N/A # filesystems cloned from these snapshots have the "zoned" 2N/A # attribute set (which is highly likely) or if they are in use 2N/A # (and can't be unmounted and re-mounted) then the snapshot 2N/A # rename will fail. So now we'll search for all the clones of 2N/A # snapshots we plan to rename and look for ones that are zoned. 2N/A # We'll ignore any snapshot clones that may be in use but are 2N/A # not zoned. If these clones are in-use, the rename will fail 2N/A # and we'll abort, there's not much else we can do about it. 2N/A # But if they are not in use the snapshot rename will unmount 2N/A # and remount the clone. This is ok because when the zoned 2N/A # attribute is off, we know that the clone was originally 2N/A # mounted from the global zone. (So unmounting and remounting 2N/A # it from the global zone is ok.) 2N/A # But we'll abort this whole operation if we find any clones 2N/A # that that are zoned and in use. (This can happen if another 2N/A # zone has been cloned from this one and is now booted.) The 2N/A # reason we do this is because those zoned filesystems could 2N/A # have originally mounted from within the zone. So if we 2N/A # cleared the zone attribute and did the rename, we'd be 2N/A # remounting the filesystem from the global zone. This would 2N/A # result in the zone losing the ability to unmount the 2N/A # filesystem, which would be bad. 2N/A # walk through all the clones 2N/A # walk through all the origin snapshots 2N/A # check if this clone originated from a snapshot that 2N/A # we need to rename. 2N/A [[ "${clones_origin[$j]}" == "${s_origin[$k]}" ]] && 2N/A [[ "${s_origin_snap[$k]}" != "${s_rename[$k]}" ]] && 2N/A # This isn't a clone of a snapshot we want to rename. 2N/A # get the zoned attr for this clone. 2N/A # This clone isn't zoned so ignore it. 2N/A # remember this clone so we can muck with it's zoned attr. 2N/A # check if it's in use 2N/A # Good news. This clone isn't in use. 2N/A # Sigh. This clone is in use so we're destined to fail. 2N/A # keep looking for errors so we can report them all at once. 2N/A # Ok. So we're finally done with planning and we can do some 2N/A # damage. We're going to: 2N/A # - destroy unused snapshots 2N/A # - unzone clones which originate from snapshots we need to rename 2N/A # - rename conflicting snapshots 2N/A # - rezone any clones which we unzoned 2N/A # - promote the oldest clone of the youngest snapshot 2N/A # - finally destroy the origin filesystem. 2N/A # delete any unsed snapshot 2N/A # rename conflicting snapshots 2N/A if [[ "${s_origin_snap[$j]}" != "${s_rename[$j]}" ]]; then 2N/A if [[ $? != 0 ]]; then 2N/A # re-zone the clones before aborting 2N/A # re-zone the clones 2N/A # promote the youngest clone of the oldest snapshot 2N/A # destroy the origin filesystem and it's descendants 2N/A# destroy_zone_datasets 2N/A# Destroys datasets associated with a zone. If the -b option is used, the 2N/A# If the -a option is used, all boot environments are destroyed. If, after 2N/A# processing -a and -b options, there are no boot environments left, all 2N/A# remaining datasets belonging to the zone are destroyed. 2N/A# Options and Arguments 2N/A# -a Destroy all boot environments 2N/A# -b <be array> Destroy the boot environments listed in this array. 2N/A# zonepath_dataset The zonepath dataset for the zone 2N/A# ZONEPATH_RDS The zone's root dataset 2N/A# destroy_zone_datasets dslist 2N/A typeset -i i # temp used while iterating 2N/A typeset -i rv=0 # return value 2N/A # It is possible that the zone structure hasn't initialized zone.path 2N/A # yet. This could be because of an interruption between the time that 2N/A # the zonepath dataset was created and the initialization or it could 2N/A # be because there is no such dataset. 2N/A # If it is still undefined, zonepath dataset doesn't exist. 2N/A # Delete any boot environments that were passed in 2N/A if (( $? != 0 )); then 2N/A # Destroy the datasets starting with the most nested 2N/A for (( i = ${#dslist[@]} - 1; i >= 0; i-- )); do 2N/A # Check to be sure that none remain 2N/A if (( $? == 0 )); then 2N/A # Check to see if rpool/ROOT is empty. If so, pretend -a was passed 2N/A # in and delete the rest of the zone datasets. 2N/A if (( $? == 0 )); then 2N/A # Destroy the datasets in an order that ensures children 2N/A for (( i = ${#dslist[@]} - 1; i >= 0; i-- )); do 2N/A vlog "Destroying zone dataset: %s" "${dslist[$i]}" 2N/A # Check to be sure that none remain 2N/A if (( $? == 0 )); then