]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: properly commit new dirfrag before splitting it 12125/head
authorYan, Zheng <zyan@redhat.com>
Tue, 22 Nov 2016 09:40:46 +0000 (17:40 +0800)
committerYan, Zheng <zyan@redhat.com>
Wed, 23 Nov 2016 07:12:58 +0000 (15:12 +0800)
CDir::is_new() check is invalid before the new directory gets
journaled. Besides, it's not good to commit a directory before
it gets journaled.

See commit 07ccc4e7 for more information.

Fixes: http://tracker.ceph.com/issues/17990
Signed-off-by: Yan, Zheng <zyan@redhat.com>
src/mds/CDir.cc
src/mds/CDir.h
src/mds/MDCache.cc
src/mds/Server.cc

index 9d20d16de6f30ef0179538f3444eefa3546ce299..07360627be86eb55cff5b5a4772d84969289c874 100644 (file)
@@ -1224,6 +1224,11 @@ void CDir::add_waiter(uint64_t tag, MDSInternalContextBase *c)
     }
   }
 
+  if (tag & WAIT_CREATED) {
+    assert(state_test(STATE_CREATING));
+    assert(state_test(STATE_FRAGMENTING));
+  }
+
   MDSCacheObject::add_waiter(tag, c);
 }
 
@@ -1335,6 +1340,13 @@ void CDir::_mark_dirty(LogSegment *ls)
 void CDir::mark_new(LogSegment *ls)
 {
   ls->new_dirfrags.push_back(&item_new);
+  state_clear(STATE_CREATING);
+
+  if (state_test(CDir::STATE_FRAGMENTING)) {
+    list<MDSInternalContextBase*> ls;
+    take_waiting(CDir::WAIT_CREATED, ls);
+    cache->mds->queue_waiters(ls);
+  }
 }
 
 void CDir::mark_clean()
index 82fecded6c58bffaaf7d298e006a5bf40255f79c..0769a9a68886a6ad4e80853815db3534804bb532 100644 (file)
@@ -99,6 +99,7 @@ public:
   static const unsigned STATE_FREEZINGDIR =   (1<< 5);
   static const unsigned STATE_COMMITTING =    (1<< 6);   // mid-commit
   static const unsigned STATE_FETCHING =      (1<< 7);   // currenting fetching
+  static const unsigned STATE_CREATING =      (1<< 8);
   static const unsigned STATE_IMPORTBOUND =   (1<<10);
   static const unsigned STATE_EXPORTBOUND =   (1<<11);
   static const unsigned STATE_EXPORTING =     (1<<12);
@@ -149,6 +150,7 @@ public:
   static const uint64_t WAIT_DENTRY       = (1<<0);  // wait for item to be in cache
   static const uint64_t WAIT_COMPLETE     = (1<<1);  // wait for complete dir contents
   static const uint64_t WAIT_FROZEN       = (1<<2);  // auth pins removed
+  static const uint64_t WAIT_CREATED     = (1<<3);  // new dirfrag is logged
 
   static const int WAIT_DNLOCK_OFFSET = 4;
 
index 06e7520b865bc4addbf3b1a2225a1487eb3b3e1a..200e82a2e9d425cc3bb1062d032a066c2d46b8ce 100644 (file)
@@ -10810,15 +10810,20 @@ void MDCache::fragment_mark_and_complete(MDRequestRef& mdr)
       dout(15) << " fetching incomplete " << *dir << dendl;
       dir->fetch(gather.new_sub(), true);  // ignore authpinnability
       ready = false;
-    }
-    if (dir->get_frag() == frag_t() && dir->is_new()) {
+    } else if (dir->get_frag() == frag_t()) {
       // The COMPLETE flag gets lost if we fragment a new dirfrag, then rollback
       // the operation. To avoid CDir::fetch() complaining about missing object,
       // we commit new dirfrag first.
-      dout(15) << " committing new " << *dir << dendl;
-      assert(dir->is_dirty());
-      dir->commit(0, gather.new_sub(), true);
-      ready = false;
+      if (dir->state_test(CDir::STATE_CREATING)) {
+       dout(15) << " waiting until new dir gets journaled " << *dir << dendl;
+       dir->add_waiter(CDir::WAIT_CREATED, gather.new_sub());
+       ready = false;
+      } else if (dir->is_new()) {
+       dout(15) << " committing new " << *dir << dendl;
+       assert(dir->is_dirty());
+       dir->commit(0, gather.new_sub(), true);
+       ready = false;
+      }
     }
     if (!ready)
       continue;
index 86b3013eb2f6b1d866695493717b800b65300ad5..fe2cfd05e937b9517d7b2ac5a0b3e0371562d884 100644 (file)
@@ -4784,6 +4784,7 @@ void Server::handle_client_mkdir(MDRequestRef& mdr)
 
   // ...and that new dir is empty.
   CDir *newdir = newi->get_or_open_dirfrag(mdcache, frag_t());
+  newdir->state_set(CDir::STATE_CREATING);
   newdir->mark_complete();
   newdir->fnode.version = newdir->pre_dirty();