From 48834afcb3856a74f51095455419eaa9f3e54d4c Mon Sep 17 00:00:00 2001 From: Shyamsundar Ranganathan Date: Mon, 24 Aug 2020 09:33:10 -0400 Subject: [PATCH] mgr/volumes: Mark subvolume root with the vxattr ceph.dir.subvolume This enables snapshot scaling of subvolumes, and hence prevents renaming, hardlinking etc. outside the subvolume. Fixes: https://tracker.ceph.com/issues/47154 Signed-off-by: Shyamsundar Ranganathan (cherry picked from commit fe0c0bd5ea1e7ebd7f2777848b9cac3966342dda) --- .../fs/operations/versions/subvolume_v1.py | 17 +++++++++++++++++ .../fs/operations/versions/subvolume_v2.py | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) 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 e008df73668c3..3d3ede5626692 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py @@ -54,6 +54,19 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): def features(self): return [SubvolumeFeatures.FEATURE_SNAPSHOT_CLONE.value, SubvolumeFeatures.FEATURE_SNAPSHOT_AUTOPROTECT.value] + def mark_subvolume(self): + # set subvolume attr, on subvolume root, marking it as a CephFS subvolume + # subvolume root is where snapshots would be taken, and hence is the dir for v1 subvolumes + xattr_val = 1 + try: + self.fs.setxattr(self.path, 'ceph.dir.subvolume', str(xattr_val).encode('utf-8'), os.XATTR_CREATE) + except cephfs.ObjectExists: + return + except cephfs.InvalidValue as e: + raise VolumeException(-errno.EINVAL, "invalid value specified for ceph.dir.subvolume: '{0}'".format(xattr_val)) + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + def snapshot_base_path(self): """ Base path for all snapshots """ return os.path.join(self.path, self.vol_spec.snapshot_dir_prefix.encode('utf-8')) @@ -77,6 +90,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): try: # create directory and set attributes self.fs.mkdirs(subvol_path, mode) + self.mark_subvolume() attrs = { 'uid': uid, 'gid': gid, @@ -138,6 +152,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): # create directory and set attributes self.fs.mkdirs(subvol_path, attrs.get("mode")) + self.mark_subvolume() self.set_attrs(subvol_path, attrs) # persist subvolume metadata and clone source @@ -200,6 +215,8 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): subvol_path = self.path log.debug("refreshed metadata, checking subvolume path '{0}'".format(subvol_path)) st = self.fs.stat(subvol_path) + # unconditionally mark as subvolume, to handle pre-existing subvolumes without the mark + self.mark_subvolume() self.uid = int(st.st_uid) self.gid = int(st.st_gid) diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py index 30003be796043..f8b6780507abf 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py @@ -93,6 +93,19 @@ class SubvolumeV2(SubvolumeV1): else: raise VolumeException(-e.args[0], e.args[1]) + def mark_subvolume(self): + # set subvolume attr, on subvolume root, marking it as a CephFS subvolume + # subvolume root is where snapshots would be taken, and hence is the base_path for v2 subvolumes + xattr_val = 1 + try: + self.fs.setxattr(self.base_path, 'ceph.dir.subvolume', str(xattr_val).encode('utf-8'), os.XATTR_CREATE) + except cephfs.ObjectExists: + return + except cephfs.InvalidValue as e: + raise VolumeException(-errno.EINVAL, "invalid value specified for ceph.dir.subvolume: '{0}'".format(xattr_val)) + except cephfs.Error as e: + raise VolumeException(-e.args[0], e.args[1]) + @staticmethod def is_valid_uuid(uuid_str): try: @@ -155,6 +168,7 @@ class SubvolumeV2(SubvolumeV1): subvol_path = os.path.join(self.base_path, str(uuid.uuid4()).encode('utf-8')) try: self.fs.mkdirs(subvol_path, mode) + self.mark_subvolume() attrs = { 'uid': uid, 'gid': gid, @@ -205,6 +219,7 @@ class SubvolumeV2(SubvolumeV1): # create directory and set attributes self.fs.mkdirs(subvol_path, attrs.get("mode")) + self.mark_subvolume() self.set_attrs(subvol_path, attrs) # persist subvolume metadata and clone source @@ -270,6 +285,8 @@ class SubvolumeV2(SubvolumeV1): op_type.value, self.subvolname)) try: self.metadata_mgr.refresh() + # unconditionally mark as subvolume, to handle pre-existing subvolumes without the mark + self.mark_subvolume() etype = self.subvol_type if op_type not in self.allowed_ops_by_type(etype): -- 2.39.5