From: Rishabh Dave Date: Wed, 14 Feb 2024 09:52:47 +0000 (+0530) Subject: mgr/vol: move reusable parts from async_cloner X-Git-Tag: testing/wip-jcollin-testing-20251001.040850-reef~4^2~4 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=4a3cb0dc4fb1d745a8f0ed7604375bb5baa806c7;p=ceph-ci.git mgr/vol: move reusable parts from async_cloner Signed-off-by: Rishabh Dave (cherry picked from commit 8c536f78907fe1d42e1df612604d5872019b501d) --- diff --git a/src/pybind/mgr/volumes/fs/async_cloner.py b/src/pybind/mgr/volumes/fs/async_cloner.py index 685b2f03c78..463c1000596 100644 --- a/src/pybind/mgr/volumes/fs/async_cloner.py +++ b/src/pybind/mgr/volumes/fs/async_cloner.py @@ -14,10 +14,12 @@ from .exception import IndexException, MetadataMgrException, OpSmException, Volu 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 @@ -49,33 +51,16 @@ def open_at_volume(fs_client, volspec, volname, groupname, subvolname, op_type): 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 @@ -84,10 +69,6 @@ def set_clone_state(fs_client, volspec, volname, groupname, subvolname, 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, @@ -221,9 +202,9 @@ def set_quota_on_clone(fs_handle, clone_volumes_pair): 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 @@ -232,14 +213,12 @@ def do_clone(fs_client, volspec, volname, groupname, subvolname, should_cancel): 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: @@ -265,24 +244,20 @@ def handle_clone_in_progress(fs_client, volspec, volname, index, groupname, subv 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) @@ -318,7 +293,7 @@ def start_clone_sm(fs_client, volspec, volname, index, groupname, subvolname, st 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] diff --git a/src/pybind/mgr/volumes/fs/operations/resolver.py b/src/pybind/mgr/volumes/fs/operations/resolver.py index c7ae8c1a310..12e77c08837 100644 --- a/src/pybind/mgr/volumes/fs/operations/resolver.py +++ b/src/pybind/mgr/volumes/fs/operations/resolver.py @@ -10,8 +10,8 @@ def splitall(path): return splitall(s[0]) + [s[1]] -def resolve(vol_spec, path): - parts = splitall(path) +def resolve_group_and_subvolume_name(vol_spec, sv_path): + parts = splitall(sv_path) if len(parts) != 4 or os.path.join(parts[0], parts[1]) != vol_spec.subvolume_prefix: return None groupname = None if parts[2] == Group.NO_GROUP_NAME else parts[2] diff --git a/src/pybind/mgr/volumes/fs/operations/subvolume.py b/src/pybind/mgr/volumes/fs/operations/subvolume.py index eed34db6ee2..f982f73bf7d 100644 --- a/src/pybind/mgr/volumes/fs/operations/subvolume.py +++ b/src/pybind/mgr/volumes/fs/operations/subvolume.py @@ -1,7 +1,8 @@ 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): @@ -72,3 +73,64 @@ def open_subvol(mgr, fs, vol_spec, group, subvolname, op_type): 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) diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py index 338727d0baf..265f4b06bd4 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py @@ -673,6 +673,11 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): raise VolumeException(-errno.EINVAL, "error fetching subvolume metadata") return clone_source + def get_clone_source(self): + src = self._get_clone_source() + return (src['volume'], src.get('group', None), src['subvolume'], + src['snapshot']) + def _get_clone_failure(self): clone_failure = { 'errno' : self.metadata_mgr.get_option(MetadataManager.CLONE_FAILURE_SECTION, MetadataManager.CLONE_FAILURE_META_KEY_ERRNO),