]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
qa/cephfs-data-scan: Validate referent hardlink recovery
authorKotresh HR <khiremat@redhat.com>
Thu, 27 Feb 2025 20:51:06 +0000 (02:21 +0530)
committerKotresh HR <khiremat@redhat.com>
Tue, 4 Mar 2025 06:20:47 +0000 (11:50 +0530)
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 <khiremat@redhat.com>
qa/tasks/cephfs/test_data_scan.py

index bee8c292edbd65ccb2feec727c949c45b60fd22e..77ca9215d50bc18f565dda5e93ebf8839aade0be 100644 (file)
@@ -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))