From: Yan, Zheng Date: Tue, 22 Nov 2016 09:40:46 +0000 (+0800) Subject: mds: properly commit new dirfrag before splitting it X-Git-Tag: v11.1.0~53^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8e83ddb3f9b0bf74f2b345cc44a7d839a7e30bd5;p=ceph.git mds: properly commit new dirfrag before splitting it 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 --- diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 9d20d16de6f3..07360627be86 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -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 ls; + take_waiting(CDir::WAIT_CREATED, ls); + cache->mds->queue_waiters(ls); + } } void CDir::mark_clean() diff --git a/src/mds/CDir.h b/src/mds/CDir.h index 82fecded6c58..0769a9a68886 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -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; diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 06e7520b865b..200e82a2e9d4 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -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; diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 86b3013eb2f6..fe2cfd05e937 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -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();