From: Yan, Zheng Date: Fri, 12 Dec 2014 02:00:53 +0000 (+0800) Subject: mds: check snaprealm before drop dentries in deleted directory X-Git-Tag: v0.93~87^2~33 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=32b1a9a1cd351c3da7e3af1948f5624969d7c1ce;p=ceph.git mds: check snaprealm before drop dentries in deleted directory There is an optimization that drop dentries in deleted directory, so that MDS can purge corresponding inode faster. We need to check if the deleted directory is still referenced by any snapshot. If it is, we can't drop dentries or skip committing dirfrags to object store. The simplest method to check if a delted directory is potentially referenced by snaphosts is checking diri->snaprealm. Signed-off-by: Yan, Zheng --- diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index c4f0713ea26d..41d3ae40c01e 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -678,23 +678,45 @@ void CDir::try_remove_dentries_for_stray() dout(10) << __func__ << dendl; assert(inode->inode.nlink == 0); + // clear dirty only when the directory was not snapshotted + bool clear_dirty = !inode->snaprealm; + 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(); - // It's OK to remove lease prematurely because we will never link - // the dentry to inode again. - if (dn->is_any_leases()) - dn->remove_client_leases(cache->mds->locker); - if (dn->get_num_ref() == 0) - remove_dentry(dn); + if (dn->last == CEPH_NOSNAP) { + if (!dn->get_linkage()->is_null() || dn->is_projected()) + continue; // shouldn't happen + if (clear_dirty && dn->is_dirty()) + dn->mark_clean(); + // It's OK to remove lease prematurely because we will never link + // the dentry to inode again. + if (dn->is_any_leases()) + dn->remove_client_leases(cache->mds->locker); + if (dn->get_num_ref() == 0) + remove_dentry(dn); + } else { + if (dn->is_projected()) + continue; // shouldn't happen + CDentry::linkage_t *dnl= dn->get_linkage(); + CInode *in = NULL; + if (dnl->is_primary()) { + in = dnl->get_inode(); + if (clear_dirty && in->is_dirty()) + in->mark_clean(); + } + if (clear_dirty && dn->is_dirty()) + dn->mark_clean(); + if (dn->get_num_ref() == 0) { + remove_dentry(dn); + if (in) + cache->remove_inode(in); + } + } } - if (is_dirty()) + if (clear_dirty && is_dirty()) mark_clean(); } @@ -1380,7 +1402,7 @@ void CDir::fetch(MDSInternalContextBase *c, const string& want_dn, bool ignore_a } // unlinked directory inode shouldn't have any entry - if (inode->inode.nlink == 0) { + if (inode->inode.nlink == 0 && !inode->snaprealm) { dout(7) << "fetch dirfrag for unlinked directory, mark complete" << dendl; if (get_version() == 0) set_version(1); @@ -1808,7 +1830,7 @@ 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) { + if (inode->inode.nlink == 0 && !inode->snaprealm) { dout(7) << "commit dirfrag for unlinked directory, mark clean" << dendl; try_remove_dentries_for_stray(); if (c) @@ -2138,6 +2160,10 @@ void CDir::_committed(int r, version_t v) p = n; } + // try drop dentries in this dirfrag if it's about to be purged + if (inode->inode.nlink == 0 && inode->snaprealm) + cache->maybe_eval_stray(inode, true); + // unpin if we kicked the last waiter. if (were_waiters && waiting_for_commit.empty()) diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 867e192e9900..7926da79b8a2 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -8942,6 +8942,12 @@ void MDCache::eval_stray(CDentry *dn, bool delay) return; // not until some snaps are deleted. } } + if (in->has_dirfrags()) { + list ls; + in->get_nested_dirfrags(ls); + for (list::iterator p = ls.begin(); p != ls.end(); ++p) + (*p)->try_remove_dentries_for_stray(); + } } if (dn->is_replicated()) { dout(20) << " replicated" << dendl; @@ -9001,16 +9007,6 @@ 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 0151675f0931..b1459cb97b94 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -907,7 +907,6 @@ 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 e31da938a0e5..0ef3fea243e2 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -5280,11 +5280,8 @@ void Server::_unlink_local_finish(MDRequestRef& mdr, dn->get_dir()->try_remove_unlinked_dn(dn); // clean up? - if (straydn) { - if (strayin->is_dir()) - mdcache->try_remove_dentries_for_stray(strayin); + if (straydn) mdcache->eval_stray(straydn); - } } bool Server::_rmdir_prepare_witness(MDRequestRef& mdr, mds_rank_t who, CDentry *dn, CDentry *straydn)