]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/volumes: Mark subvolume root with the vxattr ceph.dir.subvolume
authorShyamsundar Ranganathan <srangana@redhat.com>
Mon, 24 Aug 2020 13:33:10 +0000 (09:33 -0400)
committerShyamsundar Ranganathan <srangana@redhat.com>
Thu, 27 Aug 2020 19:42:58 +0000 (15:42 -0400)
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 <srangana@redhat.com>
(cherry picked from commit fe0c0bd5ea1e7ebd7f2777848b9cac3966342dda)

src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py
src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py

index a794d35d9acbdc9c4f5f6deaed2a4d7bf89322e5..6785c830392f599d9ccf06ae09a106f4ee70bb55 100644 (file)
@@ -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 <uuid> 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)
index 30003be796043e28816fc7c9817c3a42e11b3f16..f8b6780507abf03c0a3ea569e5bffe4f8dd3d55b 100644 (file)
@@ -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):