From: 胡玮文 Date: Thu, 16 Dec 2021 14:31:17 +0000 (+0800) Subject: mds: fix crash when exporting unlinked dir X-Git-Tag: v17.2.4~80^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1a903b525b4eae93f8efc851b84dfe46f3ff0160;p=ceph.git mds: fix crash when exporting unlinked dir 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) --- diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index b5012c340e84..7e18263d8570 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -1474,6 +1474,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; @@ -1548,16 +1562,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(); @@ -2003,17 +2010,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 c8d3e417ad49..b2dcdafde756 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;