from .fs_util import copy_file
from .operations.versions.op_sm import SubvolumeOpSm
from .operations.versions.subvolume_attrs import SubvolumeTypes, SubvolumeStates, SubvolumeActions
-from .operations.resolver import resolve
+from .operations.resolver import resolve_group_and_subvolume_name
from .operations.volume import open_volume, open_volume_lockless
from .operations.group import open_group
-from .operations.subvolume import open_subvol
+from .operations.subvolume import (open_subvol, open_subvol_in_group,
+ open_clone_subvol_pair_in_vol,
+ open_clone_subvol_pair_in_group)
from .operations.clone_index import open_clone_index
from .operations.template import SubvolumeOpType
yield subvolume
@contextmanager
-def open_at_group(fs_client, fs_handle, volspec, groupname, subvolname, op_type):
- with open_group(fs_handle, volspec, groupname) as group:
- with open_subvol(fs_client.mgr, fs_handle, volspec, group, subvolname, op_type) as subvolume:
- yield subvolume
-
-@contextmanager
-def open_at_group_unique(fs_client, fs_handle, volspec, s_groupname, s_subvolname, c_subvolume, c_groupname, c_subvolname, op_type):
+def open_at_group_unique(mgr, fs_handle, volspec, s_groupname, s_subvolname, c_subvolume, c_groupname, c_subvolname, op_type):
# if a snapshot of a retained subvolume is being cloned to recreate the same subvolume, return
# the clone subvolume as the source subvolume
if s_groupname == c_groupname and s_subvolname == c_subvolname:
yield c_subvolume
else:
- with open_at_group(fs_client, fs_handle, volspec, s_groupname, s_subvolname, op_type) as s_subvolume:
+ with open_subvol_in_group(mgr, fs_handle, volspec, s_groupname,
+ s_subvolname, op_type) as s_subvolume:
yield s_subvolume
-
-@contextmanager
-def open_clone_subvolume_pair(fs_client, fs_handle, volspec, volname, groupname, subvolname):
- with open_at_group(fs_client, fs_handle, volspec, groupname, subvolname, SubvolumeOpType.CLONE_INTERNAL) as clone_subvolume:
- s_volname, s_groupname, s_subvolname, s_snapname = get_clone_source(clone_subvolume)
- if groupname == s_groupname and subvolname == s_subvolname:
- # use the same subvolume to avoid metadata overwrites
- yield (clone_subvolume, clone_subvolume, s_snapname)
- else:
- with open_at_group(fs_client, fs_handle, volspec, s_groupname, s_subvolname, SubvolumeOpType.CLONE_SOURCE) as source_subvolume:
- yield (clone_subvolume, source_subvolume, s_snapname)
-
def get_clone_state(fs_client, volspec, volname, groupname, subvolname):
with open_at_volume(fs_client, volspec, volname, groupname, subvolname, SubvolumeOpType.CLONE_INTERNAL) as subvolume:
return subvolume.state
with open_at_volume(fs_client, volspec, volname, groupname, subvolname, SubvolumeOpType.CLONE_INTERNAL) as subvolume:
subvolume.state = (state, True)
-def get_clone_source(clone_subvolume):
- source = clone_subvolume._get_clone_source()
- return (source['volume'], source.get('group', None), source['subvolume'], source['snapshot'])
-
def get_next_state_on_error(errnum):
if errnum == -errno.EINTR:
next_state = SubvolumeOpSm.transition(SubvolumeTypes.TYPE_CLONE,
def do_clone(fs_client, volspec, volname, groupname, subvolname, should_cancel):
with open_volume_lockless(fs_client, volname) as fs_handle:
- with open_clone_subvolume_pair(fs_client, fs_handle, volspec, volname,
- groupname, subvolname) \
- as (subvol0, subvol1, subvol2):
+ with open_clone_subvol_pair_in_group(fs_client.mgr, fs_handle, volspec,
+ volname, groupname, subvolname, lockless=False) as \
+ (subvol0, subvol1, subvol2):
src_path = subvol1.snapshot_data_path(subvol2)
dst_path = subvol0.path
# XXX: this is where cloning (of subvolume's snapshots) actually
set_quota_on_clone(fs_handle, (subvol0, subvol1, subvol2))
def update_clone_failure_status(fs_client, volspec, volname, groupname, subvolname, ve):
- with open_volume_lockless(fs_client, volname) as fs_handle:
- with open_clone_subvolume_pair(fs_client, fs_handle, volspec, volname,
- groupname, subvolname) \
- as (subvol0, subvol1, subvol2) :
- if ve.errno == -errno.EINTR:
- subvol0.add_clone_failure(-ve.errno, "user interrupted clone operation")
- else:
- subvol0.add_clone_failure(-ve.errno, ve.error_str)
+ with open_clone_subvol_pair_in_vol(fs_client, volspec, volname, groupname,
+ subvolname, lockless=False) as (subvol0, subvol1, subvol2):
+ if ve.errno == -errno.EINTR:
+ subvol0.add_clone_failure(-ve.errno, "user interrupted clone operation")
+ else:
+ subvol0.add_clone_failure(-ve.errno, ve.error_str)
def log_clone_failure(volname, groupname, subvolname, ve):
if ve.errno == -errno.EINTR:
def handle_clone_failed(fs_client, volspec, volname, index, groupname, subvolname, should_cancel):
try:
- with open_volume(fs_client, volname) as fs_handle:
- # detach source but leave the clone section intact for later inspection
- with open_clone_subvolume_pair(fs_client, fs_handle, volspec,
- volname, groupname, subvolname) \
- as (subvol0, subvol1, subvol2):
- subvol1.detach_snapshot(subvol2, index)
+ # detach source but leave the clone section intact for later inspection
+ with open_clone_subvol_pair_in_vol(fs_client, volspec, volname, groupname,
+ subvolname) as (subvol0, subvol1, subvol2):
+ subvol1.detach_snapshot(subvol2, index)
except (MetadataMgrException, VolumeException) as e:
log.error("failed to detach clone from snapshot: {0}".format(e))
return (None, True)
def handle_clone_complete(fs_client, volspec, volname, index, groupname, subvolname, should_cancel):
try:
- with open_volume(fs_client, volname) as fs_handle:
- with open_clone_subvolume_pair(fs_client, fs_handle, volspec,
- volname, groupname, subvolname) \
- as (subvol0, subvol1, subvol2):
- subvol1.detach_snapshot(subvol2, index)
- subvol0.remove_clone_source(flush=True)
+ with open_clone_subvol_pair_in_vol(fs_client, volspec, volname,
+ groupname, subvolname) as (subvol0, subvol1, subvol2):
+ subvol1.detach_snapshot(subvol2, index)
+ subvol0.remove_clone_source(flush=True)
except (MetadataMgrException, VolumeException) as e:
log.error("failed to detach clone from snapshot: {0}".format(e))
return (None, True)
def clone(fs_client, volspec, volname, index, clone_path, state_table, should_cancel, snapshot_clone_delay):
log.info("cloning to subvolume path: {0}".format(clone_path))
- resolved = resolve(volspec, clone_path)
+ resolved = resolve_group_and_subvolume_name(volspec, clone_path)
groupname = resolved[0]
subvolname = resolved[1]
from contextlib import contextmanager
+from .volume import open_volume, open_volume_lockless
+from .group import open_group
from .template import SubvolumeOpType
-
from .versions import loaded_subvolumes
def create_subvol(mgr, fs, vol_spec, group, subvolname, size, isolate_nspace, pool, mode, uid, gid):
subvolume = loaded_subvolumes.get_subvolume_object(mgr, fs, vol_spec, group, subvolname)
subvolume.open(op_type)
yield subvolume
+
+
+@contextmanager
+def open_subvol_in_vol(vc, vol_spec, vol_name, group_name, subvol_name,
+ op_type, lockless=False):
+ open_vol = open_volume_lockless if lockless else open_volume
+
+ with open_vol(vc, vol_name) as vol_handle:
+ with open_group(vol_handle, vol_spec, group_name) as group:
+ with open_subvol(vc.mgr, vol_handle, vol_spec, group, subvol_name,
+ op_type) as subvol:
+ yield vol_handle, group, subvol
+
+
+@contextmanager
+def open_subvol_in_group(mgr, vol_handle, vol_spec, group_name, subvol_name,
+ op_type, lockless=False):
+ with open_group(vol_handle, vol_spec, group_name) as group:
+ with open_subvol(mgr, vol_handle, vol_spec, group, subvol_name,
+ op_type) as subvol:
+ yield subvol
+
+
+@contextmanager
+def open_clone_subvol_pair_in_vol(vc, vol_spec, vol_name, group_name,
+ subvol_name, lockless=False):
+ with open_subvol_in_vol(vc, vol_spec, vol_name, group_name, subvol_name,
+ SubvolumeOpType.CLONE_INTERNAL, lockless) \
+ as (vol_handle, _, dst_subvol):
+ src_volname, src_group_name, src_subvol_name, src_snap_name = \
+ dst_subvol.get_clone_source()
+
+ if group_name == src_group_name and subvol_name == src_subvol_name:
+ # use the same subvolume to avoid metadata overwrites
+ yield (dst_subvol, dst_subvol, src_snap_name)
+ else:
+ with open_subvol_in_group(vc.mgr, vol_handle, vol_spec,
+ src_group_name, src_subvol_name,
+ SubvolumeOpType.CLONE_SOURCE) \
+ as src_subvol:
+ yield (dst_subvol, src_subvol, src_snap_name)
+
+
+@contextmanager
+def open_clone_subvol_pair_in_group(mgr, vol_handle, vol_spec, volname,
+ group_name, subvol_name, lockless=False):
+ with open_subvol_in_group(mgr, vol_handle, vol_spec, group_name,
+ subvol_name, SubvolumeOpType.CLONE_INTERNAL,
+ lockless) as dst_subvol:
+ src_volname, src_group_name, src_subvol_name, src_snap_name = \
+ dst_subvol.get_clone_source()
+
+ if group_name == src_group_name and subvol_name == src_subvol_name:
+ # use the same subvolume to avoid metadata overwrites
+ yield (dst_subvol, dst_subvol, src_snap_name)
+ else:
+ with open_subvol_in_group(mgr, vol_handle, vol_spec,
+ src_group_name, src_subvol_name,
+ SubvolumeOpType.CLONE_SOURCE) \
+ as src_subvol:
+ yield (dst_subvol, src_subvol, src_snap_name)