]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: check for some dentry damage in scrub 47795/head
authorPatrick Donnelly <pdonnell@redhat.com>
Wed, 10 Aug 2022 17:21:26 +0000 (13:21 -0400)
committerPatrick Donnelly <pdonnell@redhat.com>
Thu, 29 Sep 2022 01:38:40 +0000 (21:38 -0400)
Fixes: https://tracker.ceph.com/issues/57091
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
src/mds/CDentry.cc
src/mds/CDentry.h
src/mds/CDir.cc
src/mds/CDir.h
src/mds/ScrubStack.cc

index 20db291556da21d9ae0df04e0491774c9b51ad1c..f76ba6579535fbb9ab1b0ac7d40941a570fe1608 100644 (file)
@@ -662,4 +662,39 @@ std::string CDentry::linkage_t::get_remote_d_type_string() const
   }
 }
 
+bool CDentry::scrub(snapid_t next_seq)
+{
+  dout(20) << "scrubbing " << *this << " next_seq = " << next_seq << dendl;
+
+  /* attempt to locate damage in first of CDentry, see:
+   * https://tracker.ceph.com/issues/56140
+   */
+  /* skip projected dentries as first/last may have placeholder values */
+  if (!is_projected()) {
+    CDir* dir = get_dir();
+
+    if (first > next_seq) {
+      derr << __func__ << ": first > next_seq (" << next_seq << ") " << *this << dendl;
+      dir->go_bad_dentry(last, get_name());
+      return true;
+    } else if (first > last) {
+      derr << __func__ << ": first > last " << *this << dendl;
+      dir->go_bad_dentry(last, get_name());
+      return true;
+    }
+
+    auto&& realm = dir->get_inode()->find_snaprealm();
+    if (realm) {
+      auto&& snaps = realm->get_snaps();
+      auto it = snaps.lower_bound(first);
+      bool stale = last != CEPH_NOSNAP && (it == snaps.end() || *it > last);
+      if (stale) {
+        dout(20) << "is stale" << dendl;
+        /* TODO: maybe trim? */
+      }
+    }
+  }
+  return false;
+}
+
 MEMPOOL_DEFINE_OBJECT_FACTORY(CDentry, co_dentry, mds_co);
index 68d5d8b34c5085cb6a38ba03fc5e8b48127820ff..ff0eb87d38252c6661cba9b10c24498edbfee6cb 100644 (file)
@@ -261,6 +261,8 @@ public:
   void mark_auth();
   void clear_auth();
   
+  bool scrub(snapid_t next_seq);
+
   // -- exporting
   // note: this assumes the dentry already exists.  
   // i.e., the name is already extracted... so we just need the other state.
index 0fc1f6c4176d778138e98e1b018e58df8022b1ff..d87ddbf63fe01c1a67817fa99a5f6ae09b698239 100644 (file)
@@ -828,7 +828,9 @@ void CDir::try_remove_dentries_for_stray()
 
 bool CDir::try_trim_snap_dentry(CDentry *dn, const set<snapid_t>& snaps)
 {
-  ceph_assert(dn->last != CEPH_NOSNAP);
+  if (dn->last == CEPH_NOSNAP) {
+    return false;
+  }
   set<snapid_t>::const_iterator p = snaps.lower_bound(dn->first);
   CDentry::linkage_t *dnl= dn->get_linkage();
   CInode *in = 0;
@@ -2553,8 +2555,7 @@ void CDir::_omap_commit(int op_prio)
     string key;
     dn->key().encode(key);
 
-    if (dn->last != CEPH_NOSNAP &&
-       snaps && try_trim_snap_dentry(dn, *snaps)) {
+    if (snaps && try_trim_snap_dentry(dn, *snaps)) {
       dout(10) << " rm " << key << dendl;
       to_remove.emplace_back(std::move(key));
       return;
index ba62a7e669d877175d50a78a3689db1e9fe00be3..6e69bc25b8e6c6365c01347893a9498d68395375 100644 (file)
@@ -323,6 +323,11 @@ public:
    */
   bool scrub_local();
 
+  /**
+   * Go bad due to a damaged dentry (register with damagetable and go BADFRAG)
+   */
+  void go_bad_dentry(snapid_t last, std::string_view dname);
+
   const scrub_info_t *scrub_info() const {
     if (!scrub_infop)
       scrub_info_create();
@@ -661,11 +666,6 @@ protected:
       double rand_threshold,
       bool *force_dirty);
 
-  /**
-   * Go bad due to a damaged dentry (register with damagetable and go BADFRAG)
-   */
-  void go_bad_dentry(snapid_t last, std::string_view dname);
-
   /**
    * Go bad due to a damaged header (register with damagetable and go BADFRAG)
    */
index 19fef8144f44e1c4f45269e0c68955132ede00db..5a3c2bf81e8538609c3efd0f41b65b085cd6fb54 100644 (file)
@@ -407,15 +407,28 @@ void ScrubStack::scrub_dirfrag(CDir *dir, bool *done)
   ScrubHeaderRef header = dir->get_scrub_header();
   version_t last_scrub = dir->scrub_info()->last_recursive.version;
   if (header->get_recursive()) {
-    for (auto it = dir->begin(); it != dir->end(); ++it) {
-      if (it->first.snapid != CEPH_NOSNAP)
+    auto next_seq = mdcache->get_global_snaprealm()->get_newest_seq()+1;
+    for (auto it = dir->begin(); it != dir->end(); /* nop */) {
+      auto [dnk, dn] = *it;
+      ++it; /* trim (in the future) may remove dentry */
+
+      if (dn->scrub(next_seq)) {
+        std::string path;
+        dir->get_inode()->make_path_string(path, true);
+        clog->warn() << "Scrub error on dentry " << *dn
+                     << " see " << g_conf()->name
+                     << " log and `damage ls` output for details";
+      }
+
+      if (dnk.snapid != CEPH_NOSNAP) {
        continue;
-      CDentry *dn = it->second;
+      }
+
       CDentry::linkage_t *dnl = dn->get_linkage();
       if (dn->get_version() <= last_scrub &&
          dnl->get_remote_d_type() != DT_DIR &&
          !header->get_force()) {
-       dout(15) << __func__ << " skip dentry " << it->first
+       dout(15) << __func__ << " skip dentry " << dnk
                 << ", no change since last scrub" << dendl;
        continue;
       }