]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
qa/test_backtrace: Validate remote_inode xattr is stored
authorKotresh HR <khiremat@redhat.com>
Thu, 27 Feb 2025 19:24:43 +0000 (00:54 +0530)
committerKotresh HR <khiremat@redhat.com>
Tue, 4 Mar 2025 06:20:47 +0000 (11:50 +0530)
Validate 'remote_inode' xattr is stored on the
referent inode upon hardlink creation if the
referent inodes feature is enabled. The value
of the xattr would be the inode number of the
primary inode.

Also validate that the referent inode is not
created on hardlink creation if the feature
is disabled.

Fixes: https://tracker.ceph.com/issues/69338
Signed-off-by: Kotresh HR <khiremat@redhat.com>
qa/tasks/cephfs/filesystem.py
qa/tasks/cephfs/test_backtrace.py

index 0ff5a28475c56d55db524390959b5586cb92fc1a..85eac792ca8e98cb50d8aae422ee58e0e841d7a3 100644 (file)
@@ -665,6 +665,9 @@ class FilesystemBase(MDSClusterBase):
     def set_allow_new_snaps(self, yes):
         self.set_var("allow_new_snaps", yes, '--yes-i-really-mean-it')
 
+    def set_allow_referent_inodes(self, yes):
+        self.set_var("allow_referent_inodes", yes)
+
     def set_bal_rank_mask(self, bal_rank_mask):
         self.set_var("bal_rank_mask", bal_rank_mask)
 
@@ -1319,9 +1322,13 @@ class FilesystemBase(MDSClusterBase):
 
             status = self.status()
 
-    def dencoder(self, obj_type, obj_blob):
-        args = [os.path.join(self._prefix, "ceph-dencoder"), 'type', obj_type, 'import', '-', 'decode', 'dump_json']
+    def dencoder(self, obj_type, obj_blob, skip=0):
+        args = [os.path.join(self._prefix, "ceph-dencoder"), 'type', obj_type]
+        if skip != 0 :
+            args.extend(["skip", str(skip)])
+        args.extend(['import', '-', 'decode', 'dump_json'])
         p = self.mon_manager.controller.run(args=args, stdin=BytesIO(obj_blob), stdout=BytesIO())
+
         return p.stdout.getvalue()
 
     def rados(self, *args, **kwargs):
@@ -1538,6 +1545,25 @@ class FilesystemBase(MDSClusterBase):
         args = ["setxattr", obj_name, xattr_name, data]
         self.rados(args, pool=pool)
 
+    def read_remote_inode(self, ino_no, pool=None):
+        """
+        Read the remote_inode xattr from the data pool, return a dict in the
+        format given by inodeno_t::dump, which is something like:
+
+        ::
+
+            rados -p cephfs_data getxattr 100000001f8.00000000 remote_inode > out.bin
+            ceph-dencoder type inodeno_t import out.bin decode dump_json
+
+            {
+                 "val": 1099511627778
+            }
+
+        :param pool: name of pool to read backtrace from.  If omitted, FS must have only
+                     one data pool and that will be used.
+        """
+        return self._read_data_xattr(ino_no, "remote_inode", "inodeno_t", pool)
+
     def read_symlink(self, ino_no, pool=None):
         return self._read_data_xattr(ino_no, "symlink", "string_wrapper", pool)
 
index cd23c114bfb86736909acdd5be6f2959a7e60908..658b8ff9f6ed8c9e2d3abf94681b0cba20744561 100644 (file)
@@ -5,8 +5,8 @@ from tasks.cephfs.filesystem import ObjectNotFound
 class TestBacktrace(CephFSTestCase):
     def test_backtrace(self):
         """
-        That the 'parent' 'layout' and 'symlink' xattrs on the head objects of files
-        are updated correctly.
+        That the 'parent', 'layout', 'symlink' and 'remote_inode' xattrs on the
+        head objects of files are updated correctly.
         """
 
         old_data_pool_name = self.fs.get_data_pool_name()
@@ -36,6 +36,33 @@ class TestBacktrace(CephFSTestCase):
             "s" : "./file1",
             })
 
+        # Disabling referent_inodes fs option should not create referent inode  and
+        # and therefore no 'remote_inode' xattr on hardlink creation
+        self.fs.set_allow_referent_inodes(False);
+        self.mount_a.run_shell(["mkdir", "hardlink_dir0"])
+        self.mount_a.run_shell(["touch", "hardlink_dir0/file1"])
+        self.mount_a.run_shell(["ln", "hardlink_dir0/file1", "hardlink_dir0/hl_file1"])
+        self.fs.mds_asok(["flush", "journal"])
+
+        file1_ino = self.mount_a.path_to_ino("hardlink_dir0/file1", follow_symlinks=False)
+        file1_inode_dump = self.fs.mds_asok(['dump', 'inode', hex(file1_ino)])
+        self.assertListEqual(file1_inode_dump['referent_inodes'], [])
+
+        # Enabling referent_inodes fs option should store 'remote_inode' xattr
+        # on hardlink creation
+        self.fs.set_allow_referent_inodes(True);
+        self.mount_a.run_shell(["mkdir", "hardlink_dir"])
+        self.mount_a.run_shell(["touch", "hardlink_dir/file1"])
+        self.mount_a.run_shell(["ln", "hardlink_dir/file1", "hardlink_dir/hl_file1"])
+        self.fs.mds_asok(["flush", "journal"])
+
+        file1_ino = self.mount_a.path_to_ino("hardlink_dir/file1", follow_symlinks=False)
+        file1_inode_dump = self.fs.mds_asok(['dump', 'inode', hex(file1_ino)])
+        referent_ino = file1_inode_dump["referent_inodes"][0]
+
+        remote_inode_xattr = self.fs.read_remote_inode(referent_ino)
+        self.assertEqual(remote_inode_xattr['val'], file1_ino)
+
         # Create a file for subsequent checks
         self.mount_a.run_shell(["mkdir", "parent_a"])
         self.mount_a.run_shell(["touch", "parent_a/alpha"])