]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/volumes: clone using cptree() from cephfs python bindings
authorRishabh Dave <ridave@redhat.com>
Fri, 7 Nov 2025 08:01:55 +0000 (13:31 +0530)
committerRishabh Dave <ridave@redhat.com>
Thu, 16 Apr 2026 12:41:08 +0000 (18:11 +0530)
Fixes: https://tracker.ceph.com/issues/72357
Signed-off-by: Rishabh Dave <ridave@redhat.com>
src/pybind/mgr/volumes/fs/async_cloner.py

index 3522c67d443b3616f8bd9323d89f3cf2de2ca1b9..d243f0906e1ae88e6216a46926ff41090098f22e 100644 (file)
@@ -113,60 +113,26 @@ def bulk_copy(fs_handle, source_path, dst_path, should_cancel):
     and regular files are synced.
     """
     log.info("copying data from {0} to {1}".format(source_path, dst_path))
-    def cptree(src_root_path, dst_root_path):
-        log.debug("cptree: {0} -> {1}".format(src_root_path, dst_root_path))
-        try:
-            with fs_handle.opendir(src_root_path) as dir_handle:
-                d = fs_handle.readdir(dir_handle)
-                while d and not should_cancel():
-                    if d.d_name not in (b".", b".."):
-                        log.debug("d={0}".format(d))
-                        d_full_src = os.path.join(src_root_path, d.d_name)
-                        d_full_dst = os.path.join(dst_root_path, d.d_name)
-                        stx = fs_handle.statx(d_full_src, cephfs.CEPH_STATX_MODE  |
-                                                          cephfs.CEPH_STATX_UID   |
-                                                          cephfs.CEPH_STATX_GID   |
-                                                          cephfs.CEPH_STATX_ATIME |
-                                                          cephfs.CEPH_STATX_MTIME |
-                                                          cephfs.CEPH_STATX_SIZE,
-                                                          cephfs.AT_SYMLINK_NOFOLLOW)
-                        handled = True
-                        mo = stx["mode"] & ~stat.S_IFMT(stx["mode"])
-                        if stat.S_ISDIR(stx["mode"]):
-                            log.debug("cptree: (DIR) {0}".format(d_full_src))
-                            try:
-                                fs_handle.fcopyfile(d_full_src, d_full_dst, mo)
-                            except cephfs.Error as e:
-                                if not e.args[0] == errno.EEXIST:
-                                    raise
-                            cptree(d_full_src, d_full_dst)
-                        elif stat.S_ISLNK(stx["mode"]):
-                            log.debug("cptree: (SYMLINK) {0}".format(d_full_src))
-                            try:
-                                fs_handle.fcopyfile(d_full_src, d_full_dst, mo)
-                            except cephfs.Error as e:
-                                if not e.args[0] == errno.EEXIST:
-                                    raise
-                        elif stat.S_ISREG(stx["mode"]):
-                            log.debug("cptree: (REG) {0}".format(d_full_src))
-                            fs_handle.fcopyfile(d_full_src, d_full_dst, mo)
-                        else:
-                            handled = False
-                            log.warning("cptree: (IGNORE) {0}".format(d_full_src))
-                        if handled:
-                            sync_attrs(fs_handle, d_full_dst, stx)
-                    d = fs_handle.readdir(dir_handle)
-                stx_root = fs_handle.statx(src_root_path, cephfs.CEPH_STATX_ATIME |
-                                                          cephfs.CEPH_STATX_MTIME,
-                                                          cephfs.AT_SYMLINK_NOFOLLOW)
-                fs_handle.lutimes(dst_root_path, (time.mktime(stx_root["atime"].timetuple()),
-                                                  time.mktime(stx_root["mtime"].timetuple())))
-        except cephfs.Error as e:
-            if not e.args[0] == errno.ENOENT:
-                raise VolumeException(-e.args[0], e.args[1])
-    cptree(source_path, dst_path)
-    if should_cancel():
+    # TODO: add code set utime on each file
+    try:
+        # src subvol's UUID must not be copied, only its contents should be.
+        # therefore cp_src_dir is set to False.
+        fs_handle.cptree(source_path, dst_path, should_sync_attrs=True,
+                         cp_src_dir=False, should_cancel=should_cancel,
+                         suppress_errors=False)
+
+        stx_root = fs_handle.statx(source_path, cephfs.CEPH_STATX_ATIME |
+                                                cephfs.CEPH_STATX_MTIME,
+                                                cephfs.AT_SYMLINK_NOFOLLOW)
+        fs_handle.lutimes(dst_path, (time.mktime(stx_root["atime"].timetuple()),
+                                     time.mktime(stx_root["mtime"].timetuple())))
+
+        log.info(f'successfully finished copying data from {source_path} to {dst_path}')
+    except cephfs.OpCanceled:
         raise VolumeException(-errno.EINTR, "user interrupted clone operation")
+    except cephfs.Error as e:
+        if e.args[0] != errno.ENOENT:
+            raise VolumeException(-e.args[0], e.args[1])
 
 def set_quota_on_clone(fs_handle, clone_volumes_pair):
     src_path = clone_volumes_pair[1].snapshot_data_path(clone_volumes_pair[2])