]> 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)
committer胡玮文 <huww98@outlook.com>
Wed, 25 May 2022 07:50:36 +0000 (15:50 +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>
src/mds/CDir.cc
src/mds/CDir.h

index aee737f82b69b8bb21d6b9985ba5302d92488896..f53e44e6f1892a710093a77b8611dbfe659f53f8 100644 (file)
@@ -1475,6 +1475,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;
@@ -1547,16 +1561,9 @@ void CDir::fetch(std::string_view dname, snapid_t last,
       pdir && pdir->inode->is_stray() && !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();
 
@@ -2043,17 +2050,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 1d87f314dcb7455502b6db577260ea1eb7ca57d8..852f86ba826e442d2a027c0894ed78a4cc4b7a6e 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;