]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: check for some dentry damage in scrub
authorPatrick Donnelly <pdonnell@redhat.com>
Wed, 10 Aug 2022 17:21:26 +0000 (13:21 -0400)
committerPatrick Donnelly <pdonnell@redhat.com>
Thu, 30 Mar 2023 02:09:49 +0000 (22:09 -0400)
Fixes: https://tracker.ceph.com/issues/57091
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
(cherry picked from commit 14712f96294ad0915951af151e4919ebf6c40cbb)

src/mds/CDentry.cc
src/mds/CDentry.h
src/mds/CDir.cc
src/mds/CDir.h
src/mds/ScrubStack.cc

index f0825d7fe11839bb82482717bc19fcf1eaccc15e..9337c11383c4d13411f9e5dfc56d62dff728ab9a 100644 (file)
@@ -642,4 +642,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 efd27719283e953d2c7a1aeb78fcc90d6e78df31..0e2a852ddd24e56c26e56e04ad2e526277920d51 100644 (file)
@@ -265,6 +265,8 @@ public:
   bool is_new() const { return state_test(STATE_NEW); }
   void clear_new() { state_clear(STATE_NEW); }
   
+  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 ba10802facd4426385dc8e596ea2783702afbc1f..b906a645efaa9515a2af1230ee74a13063d5f960 100644 (file)
@@ -800,7 +800,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;
@@ -2425,8 +2427,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 a40377b2fdd4dea760d56bd11a03f94754b2638d..7817ea398302fe20069ebe95b3e8daf7e9272a86 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();
@@ -658,11 +663,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 4bf1a7932985bce6c63753cc6a27e98880cee8d2..a54fc8b955e7965c86998298775a167eace0e50f 100644 (file)
@@ -404,15 +404,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;
       }