From: Yan, Zheng Date: Wed, 3 Dec 2014 07:32:33 +0000 (+0800) Subject: mds: drop dirty dentries in deleted directory X-Git-Tag: v0.91~52^2~18^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=818a80736c6b76c031f56708d03c263289686d51;p=ceph.git mds: drop dirty dentries in deleted directory opened dirfrags and null dirty dentries in deleted directory inode prevent MDCache::eval_stray() from purging the delete inode. It's safe to not commit null dirty dentries in deleted directory to corresponding dirfrag objects, because these dirfrag objects will be deleted soon. Fixes: #10164 Signed-off-by: Yan, Zheng --- diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index ec270769dbe..5234f710da8 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -670,6 +670,29 @@ void CDir::remove_null_dentries() { assert(get_num_any() == items.size()); } +// remove dirty null dentries for deleted directory. the dirfrag will be +// deleted soon, so it's safe to not commit dirty dentries. +void CDir::try_remove_dentries_for_stray() +{ + dout(10) << __func__ << dendl; + assert(inode->inode.nlink == 0); + + CDir::map_t::iterator p = items.begin(); + while (p != items.end()) { + CDentry *dn = p->second; + ++p; + if (!dn->get_linkage()->is_null() || dn->is_projected()) + continue; // shouldn't happen + if (dn->is_dirty()) + dn->mark_clean(); + if (dn->get_num_ref() == 0) + remove_dentry(dn); + } + + if (is_dirty()) + mark_clean(); +} + void CDir::touch_dentries_bottom() { dout(12) << "touch_dentries_bottom " << *this << dendl; @@ -1280,11 +1303,11 @@ void CDir::mark_clean() { dout(10) << "mark_clean " << *this << " version " << get_version() << dendl; if (state_test(STATE_DIRTY)) { - state_clear(STATE_DIRTY); - put(PIN_DIRTY); - item_dirty.remove_myself(); item_new.remove_myself(); + + state_clear(STATE_DIRTY); + put(PIN_DIRTY); } } @@ -1351,6 +1374,15 @@ void CDir::fetch(MDSInternalContextBase *c, const string& want_dn, bool ignore_a return; } + // unlinked directory inode shouldn't have any entry + if (inode->inode.nlink == 0) { + dout(7) << "fetch dirfrag for unlinked directory, mark complete" << dendl; + mark_complete(); + if (c) + cache->mds->queue_waiter(c); + return; + } + if (c) add_waiter(WAIT_COMPLETE, c); // already fetching? @@ -1770,6 +1802,14 @@ void CDir::commit(version_t want, MDSInternalContextBase *c, bool ignore_authpin assert(is_auth()); assert(ignore_authpinnability || can_auth_pin()); + if (inode->inode.nlink == 0) { + dout(7) << "commit dirfrag for unlinked directory, mark clean" << dendl; + try_remove_dentries_for_stray(); + if (c) + cache->mds->queue_waiter(c); + return; + } + // note: queue up a noop if necessary, so that we always // get an auth_pin. if (!c) diff --git a/src/mds/CDir.h b/src/mds/CDir.h index 4617f5573d7..00e0b470461 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -360,6 +360,7 @@ private: void purge_stale_snap_data(const std::set& snaps); public: void touch_dentries_bottom(); + void try_remove_dentries_for_stray(); bool try_trim_snap_dentry(CDentry *dn, const std::set& snaps); diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 067f360182b..b5339ba0a7e 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -8869,10 +8869,6 @@ void MDCache::eval_stray(CDentry *dn, bool delay) dout(20) << " caps | leases" << dendl; return; // wait } - if (!in->dirfrags.empty()) { - dout(20) << " open dirfrags" << dendl; - return; // wait for dirs to close/trim - } if (dn->state_test(CDentry::STATE_PURGING)) { dout(20) << " already purging" << dendl; return; // already purging @@ -8893,8 +8889,11 @@ void MDCache::eval_stray(CDentry *dn, bool delay) if (delay) { if (!dn->item_stray.is_on_list()) delayed_eval_stray.push_back(&dn->item_stray); - } else + } else { + if (in->is_dir()) + in->close_dirfrags(); purge_stray(dn); + } } else if (in->inode.nlink >= 1) { // trivial reintegrate? @@ -8917,6 +8916,16 @@ void MDCache::eval_stray(CDentry *dn, bool delay) } } +void MDCache::try_remove_dentries_for_stray(CInode* diri) { + assert(diri->inode.nlink == 0); + if (diri->has_dirfrags()) { + list ls; + diri->get_nested_dirfrags(ls); + for (list::iterator p = ls.begin(); p != ls.end(); ++p) + (*p)->try_remove_dentries_for_stray(); + } +} + void MDCache::eval_remote(CDentry *dn) { dout(10) << "eval_remote " << *dn << dendl; diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index e0fdd4dc91b..e42564092d3 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -866,6 +866,7 @@ public: dn->get_dir()->get_inode()->is_stray()) eval_stray(dn, delay); } + void try_remove_dentries_for_stray(CInode* diri); void fetch_backtrace(inodeno_t ino, int64_t pool, bufferlist& bl, Context *fin); diff --git a/src/mds/Server.cc b/src/mds/Server.cc index f8c211a11e4..5644711b0fb 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -5084,28 +5084,28 @@ void Server::_unlink_local_finish(MDRequestRef& mdr, dn->pop_projected_linkage(); // relink as stray? (i.e. was primary link?) - CDentry::linkage_t *straydnl = 0; - + CInode *strayin = NULL; bool snap_is_new = false; if (straydn) { dout(20) << " straydn is " << *straydn << dendl; - straydnl = straydn->pop_projected_linkage(); - - snap_is_new = straydnl->get_inode()->snaprealm ? true : false; + CDentry::linkage_t *straydnl = straydn->pop_projected_linkage(); + strayin = straydnl->get_inode(); + + snap_is_new = strayin->snaprealm ? true : false; mdcache->touch_dentry_bottom(straydn); } dn->mark_dirty(dnpv, mdr->ls); mdr->apply(); - if (snap_is_new) //only new if straydnl exists - mdcache->do_realm_invalidate_and_update_notify(straydnl->get_inode(), CEPH_SNAP_OP_SPLIT, true); + if (snap_is_new) //only new if strayin exists + mdcache->do_realm_invalidate_and_update_notify(strayin, CEPH_SNAP_OP_SPLIT, true); mds->mdcache->send_dentry_unlink(dn, straydn, mdr); // update subtree map? - if (straydn && straydnl->get_inode()->is_dir()) - mdcache->adjust_subtree_after_rename(straydnl->get_inode(), dn->get_dir(), true); + if (straydn && strayin->is_dir()) + mdcache->adjust_subtree_after_rename(strayin, dn->get_dir(), true); // bump pop mds->balancer->hit_dir(mdr->get_mds_stamp(), dn->get_dir(), META_POP_IWR); @@ -5113,12 +5113,15 @@ void Server::_unlink_local_finish(MDRequestRef& mdr, // reply respond_to_request(mdr, 0); - // clean up? - if (straydn) - mdcache->eval_stray(straydn); - // removing a new dn? dn->get_dir()->try_remove_unlinked_dn(dn); + + // clean up? + if (straydn) { + if (strayin->is_dir()) + mdcache->try_remove_dentries_for_stray(strayin); + mdcache->eval_stray(straydn); + } } bool Server::_rmdir_prepare_witness(MDRequestRef& mdr, mds_rank_t who, CDentry *dn, CDentry *straydn)