]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: fix crash when exporting unlinked dir
author胡玮文 <huww98@outlook.com>
Thu, 16 Dec 2021 14:31:17 +0000 (22:31 +0800)
committerXiubo Li <xiubli@redhat.com>
Tue, 19 Jul 2022 23:41:22 +0000 (07:41 +0800)
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: 胡玮文 <huww98@outlook.com>
(cherry picked from commit fcdee486697ca98a44960e6150bfd36dc34e5fe5)

src/mds/CDir.cc
src/mds/CDir.h

index b5012c340e843c00feb24d60bd5fe653da611327..7e18263d85704abe95858a3492c79c561e305bc1 100644 (file)
@@ -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<string, bufferlist>& 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<CInode*> undef_inodes;
index c8d3e417ad49a154a50de003779867198d8c8c56..b2dcdafde756b57a2f363a1290c3ddbb936fdd2c 100644 (file)
@@ -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;