From: Patrick Donnelly Date: Wed, 10 Aug 2022 17:21:26 +0000 (-0400) Subject: mds: check for some dentry damage in scrub X-Git-Tag: v16.2.13~55^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5a73de898719319fd5e9a085ceb439bebf061b92;p=ceph.git mds: check for some dentry damage in scrub Fixes: https://tracker.ceph.com/issues/57091 Signed-off-by: Patrick Donnelly (cherry picked from commit 14712f96294ad0915951af151e4919ebf6c40cbb) --- diff --git a/src/mds/CDentry.cc b/src/mds/CDentry.cc index f0825d7fe118..9337c11383c4 100644 --- a/src/mds/CDentry.cc +++ b/src/mds/CDentry.cc @@ -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); diff --git a/src/mds/CDentry.h b/src/mds/CDentry.h index efd27719283e..0e2a852ddd24 100644 --- a/src/mds/CDentry.h +++ b/src/mds/CDentry.h @@ -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. diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index ba10802facd4..b906a645efaa 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -800,7 +800,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; @@ -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; diff --git a/src/mds/CDir.h b/src/mds/CDir.h index a40377b2fdd4..7817ea398302 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(); @@ -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) */ diff --git a/src/mds/ScrubStack.cc b/src/mds/ScrubStack.cc index 4bf1a7932985..a54fc8b955e7 100644 --- a/src/mds/ScrubStack.cc +++ b/src/mds/ScrubStack.cc @@ -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; }