From 5f77f09b019b607b84e6a8f89ce19065383ca108 Mon Sep 17 00:00:00 2001 From: John Spray Date: Thu, 20 Oct 2016 11:49:08 +0100 Subject: [PATCH] tasks/cephfs: add TestForwardScrub.test_backtrace_repair Signed-off-by: John Spray --- suites/fs/recovery/tasks/forward-scrub.yaml | 1 + tasks/cephfs/filesystem.py | 24 +++++++++++++++++ tasks/cephfs/test_forward_scrub.py | 30 +++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/suites/fs/recovery/tasks/forward-scrub.yaml b/suites/fs/recovery/tasks/forward-scrub.yaml index 0a6a09cd4325f..dbbed4bf718b2 100644 --- a/suites/fs/recovery/tasks/forward-scrub.yaml +++ b/suites/fs/recovery/tasks/forward-scrub.yaml @@ -3,6 +3,7 @@ overrides: ceph: log-whitelist: - inode wrongly marked free + - bad backtrace on inode - inode table repaired for inode - Scrub error on inode diff --git a/tasks/cephfs/filesystem.py b/tasks/cephfs/filesystem.py index 3f0687512a4f6..709ed1a1c10ff 100644 --- a/tasks/cephfs/filesystem.py +++ b/tasks/cephfs/filesystem.py @@ -675,6 +675,30 @@ class Filesystem(MDSCluster): return json.loads(p.stdout.getvalue().strip()) + def _write_data_xattr(self, ino_no, xattr_name, data, pool=None): + """ + Write to an xattr of the 0th data object of an inode. Will + succeed whether the object and/or xattr already exist or not. + + :param ino_no: integer inode number + :param xattr_name: string name of the xattr + :param data: byte array data to write to the xattr + :param pool: name of data pool or None to use primary data pool + :return: None + """ + remote = self.mds_daemons[self.mds_ids[0]].remote + if pool is None: + pool = self.get_data_pool_name() + + obj_name = "{0:x}.00000000".format(ino_no) + args = [ + os.path.join(self._prefix, "rados"), "-p", pool, "setxattr", + obj_name, xattr_name, data + ] + remote.run( + args=args, + stdout=StringIO()) + def read_backtrace(self, ino_no, pool=None): """ Read the backtrace from the data pool, return a dict in the format diff --git a/tasks/cephfs/test_forward_scrub.py b/tasks/cephfs/test_forward_scrub.py index 6df9b73e33cf1..a0dc3eb3dee1e 100644 --- a/tasks/cephfs/test_forward_scrub.py +++ b/tasks/cephfs/test_forward_scrub.py @@ -262,3 +262,33 @@ class TestForwardScrub(CephFSTestCase): self.assertGreater( table['0']['data']['inotable']['free'][0]['start'], inos['./file3_sixmegs']) + + def test_backtrace_repair(self): + """ + That the MDS can repair an inodes backtrace in the data pool + if it is found to be damaged. + """ + # Create a file for subsequent checks + self.mount_a.run_shell(["mkdir", "parent_a"]) + self.mount_a.run_shell(["touch", "parent_a/alpha"]) + file_ino = self.mount_a.path_to_ino("parent_a/alpha") + + # That backtrace and layout are written after initial flush + self.fs.mds_asok(["flush", "journal"]) + backtrace = self.fs.read_backtrace(file_ino) + self.assertEqual(['alpha', 'parent_a'], + [a['dname'] for a in backtrace['ancestors']]) + + with self.assert_cluster_log("bad backtrace on inode", invert_match=True): + self.fs.mds_asok(["scrub_path", "/", "repair", "recursive"]) + + # Go corrupt the backtrace + self.fs._write_data_xattr(file_ino, "inode_backtrace_t", + "oh i'm sorry did i overwrite your xattr?") + + with self.assert_cluster_log("bad backtrace on inode"): + self.fs.mds_asok(["scrub_path", "/", "repair", "recursive"]) + self.fs.mds_asok(["flush", "journal"]) + backtrace = self.fs.read_backtrace(file_ino) + self.assertEqual(['alpha', 'parent_a'], + [a['dname'] for a in backtrace['ancestors']]) -- 2.39.5