]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
tools/cephfs-data-scan: Recover referent hardlink - build dentry
authorKotresh HR <khiremat@redhat.com>
Thu, 27 Feb 2025 18:08:51 +0000 (23:38 +0530)
committerKotresh HR <khiremat@redhat.com>
Tue, 4 Mar 2025 06:20:47 +0000 (11:50 +0530)
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 <khiremat@redhat.com>
src/cls/cephfs/cls_cephfs_client.cc
src/cls/cephfs/cls_cephfs_client.h
src/tools/cephfs/DataScan.cc
src/tools/cephfs/DataScan.h

index 00c57cc48657ce94f7332f0a713bd874bb4e7944..e3da13455babd9847f2bc852d882cedc4f9bc625 100644 (file)
@@ -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;
 }
 
index fcb328d49ea49e452288d38969340b37089f3e61..e02281185d33d4754191e8bb653f724754068cfa 100644 (file)
@@ -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(
index bdc02ed481f6530498be9a9f15fd42cc8d8c34ec..5918a229e4eb9ec60b98d3cf4fc4a39f2203a668 100644 (file)
@@ -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(
index aea9b5242ee2d7fff2b9f41c58a91498793f22bb..4aef4d626d29b951a6bafef2744e442b5e40bafb 100644 (file)
@@ -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