From: Kotresh HR Date: Thu, 27 Feb 2025 20:51:06 +0000 (+0530) Subject: qa/cephfs-data-scan: Validate referent hardlink recovery X-Git-Tag: v20.3.0~377^2~10 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=ba5df7ae75ad403d15881d2c9526eb797b0de77d;p=ceph.git qa/cephfs-data-scan: Validate referent hardlink recovery Validates that the 'cephfs-data-scan' tool recovers hardlink during disaster recovery of metadata pool from the data pool correctly as hardlink with referent inode. Fixes: https://tracker.ceph.com/issues/69338 Signed-off-by: Kotresh HR --- diff --git a/qa/tasks/cephfs/test_data_scan.py b/qa/tasks/cephfs/test_data_scan.py index bee8c292edbd6..77ca9215d50bc 100644 --- a/qa/tasks/cephfs/test_data_scan.py +++ b/qa/tasks/cephfs/test_data_scan.py @@ -164,6 +164,44 @@ class SymlinkWorkload(Workload): self.assert_equal(target, "symdir/onemegs") return self._errors +class HardlinkWorkload(Workload): + """ + Hardlink file, check that it gets recovered as hardlink + with referent inode pointing to the remote inode + """ + def write(self): + self._filesystem.set_allow_referent_inodes(True); + self._mount.run_shell(["mkdir", "hardlink_dir"]) + self._mount.write_n_mb("hardlink_dir/file1", 1) + self._mount.run_shell(["ln", "hardlink_dir/file1", "hardlink_dir/hl_file1"]) + self._mount.run_shell(["ln", "hardlink_dir/file1", "hardlink_dir/hl_file2"]) + self._filesystem.set_allow_referent_inodes(False); + + def validate(self): + self._mount.run_shell(["sudo", "ls", "hardlink_dir"], omit_sudo=False) + st_file1 = self._mount.lstat("hardlink_dir/file1") + st_hl_file1 = self._mount.lstat("hardlink_dir/hl_file1") + st_hl_file2 = self._mount.lstat("hardlink_dir/hl_file2") + # link count check + self.assert_equal(3, st_file1['st_nlink']) + self.assert_equal(3, st_hl_file1['st_nlink']) + self.assert_equal(3, st_hl_file2['st_nlink']) + # ino number check + self.assert_equal(st_file1['st_ino'], st_hl_file1['st_ino']) + self.assert_equal(st_file1['st_ino'], st_hl_file2['st_ino']) + # reverse link - referent inode list + file1_ino = self._mount.path_to_ino("hardlink_dir/file1", follow_symlinks=False) + file1_inode_dump = self._filesystem.mds_asok(['dump', 'inode', hex(file1_ino)]) + self.assert_equal(len(file1_inode_dump['referent_inodes']), 2) + # remote link + referent1_ino = file1_inode_dump['referent_inodes'][0] + referent1_inode_dump = self._filesystem.mds_asok(['dump', 'inode', hex(referent1_ino)]) + self.assert_equal(file1_ino, referent1_inode_dump['remote_ino']) + referent2_ino = file1_inode_dump['referent_inodes'][1] + referent2_inode_dump = self._filesystem.mds_asok(['dump', 'inode', hex(referent2_ino)]) + self.assert_equal(file1_ino, referent2_inode_dump['remote_ino']) + return self._errors + class NestedDirWorkload(Workload): """ Nested directories, one is lost. @@ -540,6 +578,9 @@ class TestDataScan(CephFSTestCase): def test_rebuild_symlink(self): self._rebuild_metadata(SymlinkWorkload(self.fs, self.mount_a)) + def test_rebuild_hardlink(self): + self._rebuild_metadata(HardlinkWorkload(self.fs, self.mount_a)) + def test_rebuild_nested(self): self._rebuild_metadata(NestedDirWorkload(self.fs, self.mount_a))