From 7a33e22c7d572ec8f48cd6973aa9da4737b6582b Mon Sep 17 00:00:00 2001 From: Dhairya Parmar Date: Fri, 25 Jul 2025 20:15:06 +0530 Subject: [PATCH] pybind/mgr/volumes: add getter and setter APIs for snapdir_visibility Fixes: https://tracker.ceph.com/issues/71740 Signed-off-by: Dhairya Parmar --- .../mgr/volumes/fs/operations/template.py | 1 + .../fs/operations/versions/subvolume_base.py | 59 +++++++++++++++++++ src/pybind/mgr/volumes/fs/volume.py | 35 +++++++++++ src/pybind/mgr/volumes/module.py | 30 ++++++++++ 4 files changed, 125 insertions(+) diff --git a/src/pybind/mgr/volumes/fs/operations/template.py b/src/pybind/mgr/volumes/fs/operations/template.py index 7aa953045a1..6f3ab1b7ad2 100644 --- a/src/pybind/mgr/volumes/fs/operations/template.py +++ b/src/pybind/mgr/volumes/fs/operations/template.py @@ -73,6 +73,7 @@ class SubvolumeOpType(Enum): EARMARK_GET = 'earmark-get' EARMARK_SET = 'earmark-set' EARMARK_CLEAR = 'earmark-clear' + SNAPSHOT_VISIBILITY = 'snapshot-visibility' class SubvolumeTemplate(object): VERSION = None # type: int diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py index 5dc6d14b734..74e57601dfb 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py @@ -645,3 +645,62 @@ class SubvolumeBase(object): f"subvolume={self.subvol_name} group={self.group_name} " f"reason={me.args[1]}, errno:{-me.args[0]}, {os.strerror(-me.args[0])}") raise VolumeException(-me.args[0], me.args[1]) + + def snapshot_visibility_set(self, value): + if value not in ("true", "false"): + raise VolumeException(-errno.EINVAL, "snapshot visibility value invalid") + + subvol_root_path = os.path.dirname(self.path) + subvol_v2_path = self.path + snaps_visibility_vxattr = "ceph.dir.subvolume.snaps.visible" + subvolume_size = 0 + try: + self.fs.setxattr(subvol_root_path, snaps_visibility_vxattr, + str(value).encode('utf-8'), 0) + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + + # in case of a sized subvolume, a new srnode will be assigned to the + # volumes//// path when applying + # ceph.quota.max_bytes which would assign it with the default value + # of is_snapdir_visible flag and right now the child snaprealm + # changes are not being compiled and sent to the client by MDS, so until + # that gets addressed, as a quick fix apply the vxattr on subvol root + # and the uuid path. Once the child snaprealm fix is in place, apply + # the vxattr only to subvolume root. + try: + subvolume_size = self.fs.getxattr( + subvol_v2_path, "ceph.quota.max_bytes").decode('utf-8') + except cephfs.NoData: + # should be non-sized subvol v2 path + pass + if int(subvolume_size) > 0: + try: + self.fs.setxattr(subvol_v2_path, snaps_visibility_vxattr, + str(value).encode('utf-8'), 0) + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + + try: + subvol_v2_path_snapshot_visibility = self.fs.getxattr(subvol_v2_path, + snaps_visibility_vxattr).decode('utf-8') + if bool(subvol_v2_path_snapshot_visibility) != bool(value): + raise VolumeException(-errno.EINVAL, "could not set " + f"{snaps_visibility_vxattr} to {value} " + f"on subvolume v2 path {subvol_v2_path}") + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + + try: + return self.fs.getxattr(subvol_root_path, + snaps_visibility_vxattr).decode('utf-8') + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + + def snapshot_visibility_get(self): + subvol_parent_path = os.path.dirname(self.path) + try: + return self.fs.getxattr(subvol_parent_path, + "ceph.dir.subvolume.snaps.visible").decode('utf-8') + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) diff --git a/src/pybind/mgr/volumes/fs/volume.py b/src/pybind/mgr/volumes/fs/volume.py index bd34faeafb5..e556b8f4f4f 100644 --- a/src/pybind/mgr/volumes/fs/volume.py +++ b/src/pybind/mgr/volumes/fs/volume.py @@ -1325,3 +1325,38 @@ class VolumeClient(CephfsClient["Module"]): except VolumeException as ve: ret = self.volume_exception_to_retval(ve) return ret + + def subvolume_snapshot_visibility_set(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + groupname = kwargs['group_name'] + value = kwargs['value'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + with open_subvol(self.mgr, fs_handle, self.volspec, group, subvolname, + SubvolumeOpType.SNAPSHOT_VISIBILITY) as subvolume: + v = subvolume.snapshot_visibility_set(value) + ret = 0, v, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret + + def subvolume_snapshot_visibility_get(self, **kwargs): + ret = 0, "", "" + volname = kwargs['vol_name'] + subvolname = kwargs['sub_name'] + groupname = kwargs['group_name'] + + try: + with open_volume(self, volname) as fs_handle: + with open_group(fs_handle, self.volspec, groupname) as group: + with open_subvol(self.mgr, fs_handle, self.volspec, group, subvolname, + SubvolumeOpType.SNAPSHOT_VISIBILITY) as subvolume: + v = subvolume.snapshot_visibility_get() + ret = 0, v, "" + except VolumeException as ve: + ret = self.volume_exception_to_retval(ve) + return ret diff --git a/src/pybind/mgr/volumes/module.py b/src/pybind/mgr/volumes/module.py index 6f7f1b3fd15..59711221bf1 100644 --- a/src/pybind/mgr/volumes/module.py +++ b/src/pybind/mgr/volumes/module.py @@ -576,6 +576,23 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): 'desc': "Cancel an pending or ongoing clone operation.", 'perm': 'r' }, + { + 'cmd': 'fs subvolume snapshot_visibility set' + ' name=vol_name,type=CephString' + ' name=sub_name,type=CephString' + ' name=value,type=CephString,req=true' + ' name=group_name,type=CephString,req=false', + 'desc': "Set snapdir visibility for subvolume", + 'perm': 'rw' + }, + { + 'cmd': 'fs subvolume snapshot_visibility get' + ' name=vol_name,type=CephString' + ' name=sub_name,type=CephString' + ' name=group_name,type=CephString,req=false', + 'desc': "Get snapdir visibility for subvolume", + 'perm': 'rw' + }, # volume ls [recursive] # subvolume ls # volume authorize/deauthorize @@ -1097,3 +1114,16 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): return self.vc.subvolume_info(vol_name=vol_name, sub_name=subvol, group_name=group_name) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_snapshot_visibility_set(self, inbuf, cmd): + return self.vc.subvolume_snapshot_visibility_set(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + value=cmd['value'], + group_name=cmd.get('group_name', None)) + + @mgr_cmd_wrap + def _cmd_fs_subvolume_snapshot_visibility_get(self, inbuf, cmd): + return self.vc.subvolume_snapshot_visibility_get(vol_name=cmd['vol_name'], + sub_name=cmd['sub_name'], + group_name=cmd.get('group_name', None)) -- 2.39.5