From 4e0f7dbd558cf6672fd40536e8f1ef86d1995b5a Mon Sep 17 00:00:00 2001 From: Kotresh HR Date: Fri, 28 Feb 2025 00:54:43 +0530 Subject: [PATCH] qa/test_backtrace: Validate remote_inode xattr is stored 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 --- qa/tasks/cephfs/filesystem.py | 30 ++++++++++++++++++++++++++++-- qa/tasks/cephfs/test_backtrace.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/qa/tasks/cephfs/filesystem.py b/qa/tasks/cephfs/filesystem.py index 0ff5a28475c56..85eac792ca8e9 100644 --- a/qa/tasks/cephfs/filesystem.py +++ b/qa/tasks/cephfs/filesystem.py @@ -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) diff --git a/qa/tasks/cephfs/test_backtrace.py b/qa/tasks/cephfs/test_backtrace.py index cd23c114bfb86..658b8ff9f6ed8 100644 --- a/qa/tasks/cephfs/test_backtrace.py +++ b/qa/tasks/cephfs/test_backtrace.py @@ -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"]) -- 2.39.5