From 689ae238b8a5a4e7cd94f9c5df350d29e1aae44b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E8=83=A1=E7=8E=AE=E6=96=87?= Date: Thu, 16 Dec 2021 22:31:17 +0800 Subject: [PATCH] mds: fix crash when exporting unlinked dir MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When fetch() an unlinked dir, we set fnode->version = 1, but leave projected_version = 0. This will trigger the assert `dir->get_projected_version() == dir->get_version()` in Migrator::encode_export_dir(). projected_version should equal to `fnode->version` unless this dir is projected. Fix this by introducing a new helper CDir::set_fresh_fnode(), which will ensure versions are correctly set. Fixes: https://tracker.ceph.com/issues/53597 Signed-off-by: 胡玮文 (cherry picked from commit fcdee486697ca98a44960e6150bfd36dc34e5fe5) --- src/mds/CDir.cc | 35 ++++++++++++++++------------------- src/mds/CDir.h | 1 + 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 50ce6b15f21..e9b9c38d255 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -1472,6 +1472,20 @@ void CDir::mark_new(LogSegment *ls) mdcache->mds->queue_waiters(waiters); } +void CDir::set_fresh_fnode(fnode_const_ptr&& ptr) { + ceph_assert(inode->is_auth()); + ceph_assert(!is_projected()); + ceph_assert(!state_test(STATE_COMMITTING)); + reset_fnode(std::move(ptr)); + projected_version = committing_version = committed_version = get_version(); + + if (state_test(STATE_REJOINUNDEF)) { + ceph_assert(mdcache->mds->is_rejoin()); + state_clear(STATE_REJOINUNDEF); + mdcache->opened_undef_dirfrag(this); + } +} + void CDir::mark_clean() { dout(10) << __func__ << " " << *this << " version " << get_version() << dendl; @@ -1546,16 +1560,9 @@ void CDir::fetch(MDSContext *c, std::string_view want_dn, bool ignore_authpinnab !inode->snaprealm) { dout(7) << "fetch dirfrag for unlinked directory, mark complete" << dendl; if (get_version() == 0) { - ceph_assert(inode->is_auth()); auto _fnode = allocate_fnode(); _fnode->version = 1; - reset_fnode(std::move(_fnode)); - - if (state_test(STATE_REJOINUNDEF)) { - ceph_assert(mdcache->mds->is_rejoin()); - state_clear(STATE_REJOINUNDEF); - mdcache->opened_undef_dirfrag(this); - } + set_fresh_fnode(std::move(_fnode)); } mark_complete(); @@ -2001,17 +2008,7 @@ void CDir::_omap_fetched(bufferlist& hdrbl, map& omap, // take the loaded fnode? // only if we are a fresh CDir* with no prior state. if (get_version() == 0) { - ceph_assert(!is_projected()); - ceph_assert(!state_test(STATE_COMMITTING)); - auto _fnode = allocate_fnode(got_fnode); - reset_fnode(std::move(_fnode)); - projected_version = committing_version = committed_version = get_version(); - - if (state_test(STATE_REJOINUNDEF)) { - ceph_assert(mdcache->mds->is_rejoin()); - state_clear(STATE_REJOINUNDEF); - mdcache->opened_undef_dirfrag(this); - } + set_fresh_fnode(allocate_fnode(got_fnode)); } list undef_inodes; diff --git a/src/mds/CDir.h b/src/mds/CDir.h index a6793e6a837..4e189e27385 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -247,6 +247,7 @@ public: void reset_fnode(fnode_const_ptr&& ptr) { fnode = std::move(ptr); } + void set_fresh_fnode(fnode_const_ptr&& ptr); const fnode_const_ptr& get_fnode() const { return fnode; -- 2.47.3