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)
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):
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)
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()
"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"])