From 26ace8cf4549ae239b5e41dc161366dd6af565d1 Mon Sep 17 00:00:00 2001 From: Venky Shankar Date: Fri, 7 Feb 2020 00:26:03 -0500 Subject: [PATCH] mgr/volumes: synchronize inode attributes for cloned subvolumes Synchronize ownership, permission and inode timestamp (access and modification times) for all supported inode types. Note that inode timestamps are synchronized upto seconds granularity. Signed-off-by: Venky Shankar (cherry picked from commit aac6b5f1cef7d055bdde797519aece779d06fb41) Conflicts: src/pybind/mgr/volumes/fs/async_cloner.py - uid and gid arguments of chown() and copy_file() were type converted to `int` for nautilus. --- src/pybind/mgr/volumes/fs/async_cloner.py | 39 ++++++++++++++++++----- src/pybind/mgr/volumes/fs/fs_util.py | 3 +- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/pybind/mgr/volumes/fs/async_cloner.py b/src/pybind/mgr/volumes/fs/async_cloner.py index 88dac61b74be5..6d25ebae53001 100644 --- a/src/pybind/mgr/volumes/fs/async_cloner.py +++ b/src/pybind/mgr/volumes/fs/async_cloner.py @@ -72,6 +72,15 @@ def handle_clone_pending(volume_client, volname, index, groupname, subvolname, s raise VolumeException(oe.error, oe.error_str) return (next_state, False) +def sync_attrs(fs_handle, target_path, source_statx): + try: + fs_handle.lchown(target_path, source_statx["uid"], source_statx["gid"]) + fs_handle.lutimes(target_path, (time.mktime(source_statx["atime"].timetuple()), + time.mktime(source_statx["mtime"].timetuple()))) + except cephfs.Error as e: + log.warn("error synchronizing attrs for {0} ({1})".format(target_path, e)) + raise e + def bulk_copy(fs_handle, source_path, dst_path, should_cancel): """ bulk copy data from source to destination -- only directories, symlinks @@ -90,31 +99,45 @@ def bulk_copy(fs_handle, source_path, dst_path, should_cancel): 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) - st = fs_handle.lstat(d_full_src) - mo = st.st_mode & ~stat.S_IFMT(st.st_mode) - if stat.S_ISDIR(st.st_mode): + 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.mkdir(d_full_dst, mo) - fs_handle.chown(d_full_dst, int(st.st_uid), int(st.st_gid)) except cephfs.Error as e: if not e.args[0] == errno.EEXIST: raise cptree(d_full_src, d_full_dst) - elif stat.S_ISLNK(st.st_mode): + elif stat.S_ISLNK(stx["mode"]): log.debug("cptree: (SYMLINK) {0}".format(d_full_src)) target = fs_handle.readlink(d_full_src, 4096) try: - fs_handle.symlink(target[:st.st_size], d_full_dst) + fs_handle.symlink(target[:stx["size"]], d_full_dst) except cephfs.Error as e: if not e.args[0] == errno.EEXIST: raise - elif stat.S_ISREG(st.st_mode): + elif stat.S_ISREG(stx["mode"]): log.debug("cptree: (REG) {0}".format(d_full_src)) - copy_file(fs_handle, d_full_src, d_full_dst, mo, int(st.st_uid), int(st.st_gid)) + copy_file(fs_handle, d_full_src, d_full_dst, mo) else: + handled = False log.warn("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]) diff --git a/src/pybind/mgr/volumes/fs/fs_util.py b/src/pybind/mgr/volumes/fs/fs_util.py index 7dd116e5fb358..524f56a2ab0f2 100644 --- a/src/pybind/mgr/volumes/fs/fs_util.py +++ b/src/pybind/mgr/volumes/fs/fs_util.py @@ -86,7 +86,7 @@ def list_one_entry_at_a_time(fs, dirpath): except cephfs.Error as e: raise VolumeException(-e.args[0], e.args[1]) -def copy_file(fs, src, dst, mode, uid, gid): +def copy_file(fs, src, dst, mode): """ Copy a regular file from @src to @dst. @dst is overwritten if it exists. """ @@ -94,7 +94,6 @@ def copy_file(fs, src, dst, mode, uid, gid): try: src_fd = fs.open(src, os.O_RDONLY); dst_fd = fs.open(dst, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, mode) - fs.chown(dst, uid, gid) except cephfs.Error as e: if src_fd is not None: fs.close(src_fd) -- 2.39.5