From 14712f96294ad0915951af151e4919ebf6c40cbb Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Wed, 10 Aug 2022 13:21:26 -0400 Subject: [PATCH] mds: check for some dentry damage in scrub Fixes: https://tracker.ceph.com/issues/57091 Signed-off-by: Patrick Donnelly --- src/mds/CDentry.cc | 35 +++++++++++++++++++++++++++++++++++ src/mds/CDentry.h | 2 ++ src/mds/CDir.cc | 7 ++++--- src/mds/CDir.h | 10 +++++----- src/mds/ScrubStack.cc | 21 +++++++++++++++++---- 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/mds/CDentry.cc b/src/mds/CDentry.cc index 20db291556d..f76ba657953 100644 --- a/src/mds/CDentry.cc +++ b/src/mds/CDentry.cc @@ -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); diff --git a/src/mds/CDentry.h b/src/mds/CDentry.h index 68d5d8b34c5..ff0eb87d382 100644 --- a/src/mds/CDentry.h +++ b/src/mds/CDentry.h @@ -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. diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 0fc1f6c4176..d87ddbf63fe 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -828,7 +828,9 @@ void CDir::try_remove_dentries_for_stray() bool CDir::try_trim_snap_dentry(CDentry *dn, const set& snaps) { - ceph_assert(dn->last != CEPH_NOSNAP); + if (dn->last == CEPH_NOSNAP) { + return false; + } set::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; diff --git a/src/mds/CDir.h b/src/mds/CDir.h index ba62a7e669d..6e69bc25b8e 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -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) */ diff --git a/src/mds/ScrubStack.cc b/src/mds/ScrubStack.cc index 19fef8144f4..5a3c2bf81e8 100644 --- a/src/mds/ScrubStack.cc +++ b/src/mds/ScrubStack.cc @@ -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; } -- 2.47.3