From 7701f49681f0ba37af2fe1e31144ceb27114d1f5 Mon Sep 17 00:00:00 2001 From: Xuehan Xu Date: Fri, 8 Jun 2018 22:29:30 +0800 Subject: [PATCH] mds: avoid traversing all dirfrags when trying to get wrlocks Fixes: http://tracker.ceph.com/issues/24467 Signed-off-by: Xuehan Xu (cherry picked from commit da02fbcb0afd1b72d6c030f06613d8b18028a13c) --- src/mds/CDir.cc | 12 +++++++----- src/mds/CDir.h | 9 +++++++++ src/mds/CInode.cc | 20 ++++++++++++-------- src/mds/CInode.h | 7 +++++++ src/mds/MDCache.cc | 3 --- src/mds/Migrator.cc | 10 +++++----- 6 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index e6796ee37c8e7..bce25b1fd7c7e 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -1017,10 +1017,7 @@ void CDir::split(int bits, list& subs, list& wai CDir *f = new CDir(inode, *p, cache, is_auth()); f->state_set(state & (MASK_STATE_FRAGMENT_KEPT | STATE_COMPLETE)); f->get_replicas() = get_replicas(); - f->dir_auth = dir_auth; - f->init_fragment_pins(); f->set_version(get_version()); - f->pop_me = pop_me; f->pop_me.scale(fac); @@ -1038,6 +1035,7 @@ void CDir::split(int bits, list& subs, list& wai f->set_dir_auth(get_dir_auth()); f->prepare_new_fragment(replay); + f->init_fragment_pins(); } // repartition dentries @@ -2657,7 +2655,9 @@ void CDir::set_dir_auth(const mds_authority_t &a) // new subtree root? if (!was_subtree && is_subtree_root()) { dout(10) << " new subtree root, adjusting auth_pins" << dendl; - + + inode->num_subtree_roots++; + // adjust nested auth pins if (get_cum_auth_pins()) inode->adjust_nested_auth_pins(-1, NULL); @@ -2671,7 +2671,9 @@ void CDir::set_dir_auth(const mds_authority_t &a) } if (was_subtree && !is_subtree_root()) { dout(10) << " old subtree root, adjusting auth_pins" << dendl; - + + inode->num_subtree_roots--; + // adjust nested auth pins if (get_cum_auth_pins()) inode->adjust_nested_auth_pins(1, NULL); diff --git a/src/mds/CDir.h b/src/mds/CDir.h index 5739e907ba5d2..4597b7ddb5016 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -181,6 +181,15 @@ public: void assimilate_dirty_rstat_inodes(); void assimilate_dirty_rstat_inodes_finish(MutationRef& mut, EMetaBlob *blob); + void mark_exporting() { + state_set(CDir::STATE_EXPORTING); + inode->num_exporting_dirs++; + } + void clear_exporting() { + state_clear(CDir::STATE_EXPORTING); + inode->num_exporting_dirs--; + } + protected: version_t projected_version; mempool::mds_co::list projected_fnode; diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 4b9379cc781d3..3ca0f4f4fefb6 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -769,6 +769,9 @@ void CInode::close_dirfrag(frag_t fg) dir->state_clear(CDir::STATE_STICKY); dir->put(CDir::PIN_STICKY); } + + if (dir->is_subtree_root()) + num_subtree_roots--; // dump any remaining dentries, for debugging purposes for (const auto &p : dir->items) @@ -787,21 +790,22 @@ void CInode::close_dirfrags() bool CInode::has_subtree_root_dirfrag(int auth) { - for (const auto &p : dirfrags) { - if (p.second->is_subtree_root() && - (auth == -1 || p.second->dir_auth.first == auth)) + if (num_subtree_roots > 0) { + if (auth == -1) return true; + for (const auto &p : dirfrags) { + if (p.second->is_subtree_root() && + p.second->dir_auth.first == auth) + return true; + } } return false; } bool CInode::has_subtree_or_exporting_dirfrag() { - for (const auto &p : dirfrags) { - if (p.second->is_subtree_root() || - p.second->state_test(CDir::STATE_EXPORTING)) - return true; - } + if (num_subtree_roots > 0 || num_exporting_dirs > 0) + return true; return false; } diff --git a/src/mds/CInode.h b/src/mds/CInode.h index ddf2c4bd46dbb..e0e37e9644c9f 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -538,6 +538,11 @@ public: // -- cache infrastructure -- private: mempool::mds_co::compact_map dirfrags; // cached dir fragments under this Inode + + //for the purpose of quickly determining whether there's a subtree root or exporting dir + int num_subtree_roots = 0; + int num_exporting_dirs = 0; + int stickydir_ref = 0; scrub_info_t *scrub_infop = nullptr; @@ -712,6 +717,8 @@ public: assert(num_projected_xattrs == 0); assert(num_projected_srnodes == 0); assert(num_caps_wanted == 0); + assert(num_subtree_roots == 0); + assert(num_exporting_dirs == 0); } diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index d82da8741d678..64b442b9d58b1 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -10997,9 +10997,6 @@ void MDCache::adjust_dir_fragments(CInode *diri, } show_subtrees(10); - - // dir has no PIN_SUBTREE; CDir::purge_stolen() drops it. - dir->dir_auth = CDIR_AUTH_DEFAULT; } diri->close_dirfrag(dir->get_frag()); diff --git a/src/mds/Migrator.cc b/src/mds/Migrator.cc index b7e1b03ea885f..770451eab878c 100644 --- a/src/mds/Migrator.cc +++ b/src/mds/Migrator.cc @@ -370,7 +370,7 @@ void Migrator::export_try_cancel(CDir *dir, bool notify_peer) if (it->second.state == EXPORT_CANCELLED) { export_state.erase(it); - dir->state_clear(CDir::STATE_EXPORTING); + dir->clear_exporting(); // send pending import_maps? cache->maybe_send_pending_resolves(); } @@ -395,7 +395,7 @@ void Migrator::export_try_cancel(CDir *dir, bool notify_peer) void Migrator::export_cancel_finish(CDir *dir) { assert(dir->state_test(CDir::STATE_EXPORTING)); - dir->state_clear(CDir::STATE_EXPORTING); + dir->clear_exporting(); // pinned by Migrator::export_notify_abort() dir->auth_unpin(this); @@ -860,7 +860,7 @@ void Migrator::export_dir(CDir *dir, mds_rank_t dest) mds->hit_export_target(ceph_clock_now(), dest, -1); dir->auth_pin(this); - dir->state_set(CDir::STATE_EXPORTING); + dir->mark_exporting(); MDRequestRef mdr = mds->mdcache->request_start_internal(CEPH_MDS_OP_EXPORTDIR); mdr->more()->export_dir = dir; @@ -1074,7 +1074,7 @@ void Migrator::export_frozen(CDir *dir, uint64_t tid) mds->send_message_mds(new MExportDirCancel(dir->dirfrag(), it->second.tid), it->second.peer); export_state.erase(it); - dir->state_clear(CDir::STATE_EXPORTING); + dir->clear_exporting(); cache->maybe_send_pending_resolves(); return; } @@ -2071,7 +2071,7 @@ void Migrator::export_finish(CDir *dir) MutationRef mut = it->second.mut; // remove from exporting list, clean up state export_state.erase(it); - dir->state_clear(CDir::STATE_EXPORTING); + dir->clear_exporting(); cache->show_subtrees(); audit(); -- 2.39.5