From: Kotresh HR Date: Thu, 27 Feb 2025 18:08:51 +0000 (+0530) Subject: tools/cephfs-data-scan: Recover referent hardlink - build dentry X-Git-Tag: v20.3.0~377^2~13 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3d4ac8c82fe7a67a984a343d8fbd270a8e92ed9d;p=ceph.git tools/cephfs-data-scan: Recover referent hardlink - build dentry The 'remote_inode' xattr is stored on the referent inode in data pool. This patch uses this xattr to build the hardlink dentry as part of the sub command 'scan_inodes' of the cephfs-data-scan. Fixes: https://tracker.ceph.com/issues/69338 Signed-off-by: Kotresh HR --- diff --git a/src/cls/cephfs/cls_cephfs_client.cc b/src/cls/cephfs/cls_cephfs_client.cc index 00c57cc4865..e3da13455ba 100644 --- a/src/cls/cephfs/cls_cephfs_client.cc +++ b/src/cls/cephfs/cls_cephfs_client.cc @@ -85,6 +85,7 @@ int ClsCephFSClient::fetch_inode_accumulate_result( inode_backtrace_t *backtrace, file_layout_t *layout, std::string *symlink, + inodeno_t *remote_inode, AccumulateResult *result) { ceph_assert(backtrace != NULL); @@ -124,6 +125,11 @@ int ClsCephFSClient::fetch_inode_accumulate_result( op.getxattr("symlink", &symlink_bl, &symlink_r); op.set_op_flags2(librados::OP_FAILOK); + int remote_inode_r = 0; + bufferlist remote_inode_bl; + op.getxattr("remote_inode", &remote_inode_bl, &remote_inode_r); + op.set_op_flags2(librados::OP_FAILOK); + bufferlist op_bl; int r = ctx.operate(oid, &op, &op_bl); if (r < 0) { @@ -202,6 +208,16 @@ int ClsCephFSClient::fetch_inode_accumulate_result( } } + // Deserialize remote_inode + if (remote_inode_bl.length()) { + try { + auto q = remote_inode_bl.cbegin(); + decode(*remote_inode, q); + } catch (ceph::buffer::error &e) { + return -EINVAL; + } + } + return 0; } diff --git a/src/cls/cephfs/cls_cephfs_client.h b/src/cls/cephfs/cls_cephfs_client.h index fcb328d49ea..e02281185d3 100644 --- a/src/cls/cephfs/cls_cephfs_client.h +++ b/src/cls/cephfs/cls_cephfs_client.h @@ -25,6 +25,7 @@ class ClsCephFSClient inode_backtrace_t *backtrace, file_layout_t *layout, std::string *symlink, + inodeno_t *remote_inode, AccumulateResult *result); static int delete_inode_accumulate_result( diff --git a/src/tools/cephfs/DataScan.cc b/src/tools/cephfs/DataScan.cc index bdc02ed481f..5918a229e4e 100644 --- a/src/tools/cephfs/DataScan.cc +++ b/src/tools/cephfs/DataScan.cc @@ -767,8 +767,9 @@ int DataScan::scan_inodes() inode_backtrace_t backtrace; file_layout_t loaded_layout = file_layout_t::get_default(); std::string symlink; + inodeno_t remote_inode; r = ClsCephFSClient::fetch_inode_accumulate_result( - data_io, oid, &backtrace, &loaded_layout, &symlink, &accum_res); + data_io, oid, &backtrace, &loaded_layout, &symlink, &remote_inode, &accum_res); if (r == -EINVAL) { dout(4) << "Accumulated metadata missing from '" @@ -964,7 +965,7 @@ int DataScan::scan_inodes() } InodeStore dentry; - build_file_dentry(obj_name_ino, file_size, file_mtime, guessed_layout, &dentry, symlink); + build_file_dentry(obj_name_ino, file_size, file_mtime, guessed_layout, symlink, remote_inode, &dentry); // Inject inode to the metadata pool if (have_backtrace) { @@ -1216,14 +1217,40 @@ int DataScan::scan_links() dout(20) << "adding " << ino << " for future processing to fix dnfirst" << dendl; } } - } else if (dentry_type == 'L' || dentry_type == 'l') { + } else if (dentry_type == 'L' || dentry_type == 'l' || dentry_type == 'R' || dentry_type == 'r') { inodeno_t ino; + inodeno_t referent_ino; + InodeStore inode; unsigned char d_type; - CDentry::decode_remote(dentry_type, ino, d_type, alternate_name, q); + + if (dentry_type == 'r') { + DECODE_START(2, q); + if (struct_v >= 2) + decode(alternate_name, q); + dout(20) << "decoding referent inode dentry type 'r' 0x" << std::hex << dir_ino << std::dec << "/" << dname << dendl; + inode.decode(q); + DECODE_FINISH(q); + ino = inode.inode->remote_ino; + referent_ino = inode.inode->ino; + } else if (dentry_type == 'R') { + dout(20) << "decoding referent inode dentry type 'R' 0x" << std::hex << dir_ino << std::dec << "/" << dname << dendl; + inode.decode_bare(q); + ino = inode.inode->remote_ino; + referent_ino = inode.inode->ino; + } else { + CDentry::decode_remote(dentry_type, ino, d_type, alternate_name, q); + } if (step == SCAN_INOS) { - remote_links[ino]++; + dout(20) << "Add referent inode dentry 0x" << std::hex << dir_ino << std::dec << "/" << dname << " to used_inos" << dendl; + used_inos.insert(referent_ino); + dout(20) << "Add referent inode dentry 0x" << std::hex << dir_ino << std::dec << "/" << dname << " to remote_links" << dendl; + remote_links[ino]++; } else if (step == CHECK_LINK) { + if (dnfirst == CEPH_NOSNAP) { + injected_inos.insert({referent_ino, link_info_t(dir_ino, frag_id, dname, inode.inode)}); + dout(20) << "Adding referent inode " << referent_ino << " for future processing to fix dnfirst" << dendl; + } if (!used_inos.contains(ino, 1)) { derr << "Bad remote link dentry 0x" << std::hex << dir_ino << std::dec << "/" << dname @@ -1683,8 +1710,8 @@ int MetadataTool::read_dentry(inodeno_t parent_ino, frag_t frag, decode(first, q); char dentry_type; decode(dentry_type, q); - if (dentry_type == 'I' || dentry_type == 'i') { - if (dentry_type == 'i') { + if (dentry_type == 'I' || dentry_type == 'i' || dentry_type == 'R' || dentry_type == 'r') { + if (dentry_type == 'i' || dentry_type == 'r') { mempool::mds_co::string alternate_name; DECODE_START(2, q); @@ -2168,7 +2195,10 @@ int MetadataDriver::inject_linkage( bufferlist dentry_bl; encode(dnfirst, dentry_bl); - encode('I', dentry_bl); + if (inode.inode->remote_ino) + encode('R', dentry_bl); + else + encode('I', dentry_bl); inode.encode_bare(dentry_bl, CEPH_FEATURES_SUPPORTED_DEFAULT); // Write out @@ -2343,7 +2373,8 @@ int LocalFileDriver::check_roots(bool *result) void MetadataTool::build_file_dentry( inodeno_t ino, uint64_t file_size, time_t file_mtime, - const file_layout_t &layout, InodeStore *out, std::string symlink) + const file_layout_t &layout, std::string symlink, inodeno_t remote_inode, + InodeStore *out) { ceph_assert(out != NULL); @@ -2375,6 +2406,7 @@ void MetadataTool::build_file_dentry( inode->backtrace_version = 1; inode->uid = g_conf()->mds_root_ino_uid; inode->gid = g_conf()->mds_root_ino_gid; + inode->remote_ino = remote_inode; } void MetadataTool::build_dir_dentry( diff --git a/src/tools/cephfs/DataScan.h b/src/tools/cephfs/DataScan.h index aea9b5242ee..4aef4d626d2 100644 --- a/src/tools/cephfs/DataScan.h +++ b/src/tools/cephfs/DataScan.h @@ -154,8 +154,9 @@ class MetadataTool void build_file_dentry( inodeno_t ino, uint64_t file_size, time_t file_mtime, const file_layout_t &layout, - InodeStore *out, - std::string symlink); + std::string symlink, + inodeno_t remote_inode, + InodeStore *out); /** * Construct a synthetic InodeStore for a directory