]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: check snaprealm before drop dentries in deleted directory
authorYan, Zheng <zyan@redhat.com>
Fri, 12 Dec 2014 02:00:53 +0000 (10:00 +0800)
committerYan, Zheng <zyan@redhat.com>
Thu, 5 Feb 2015 14:40:37 +0000 (22:40 +0800)
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 <zyan@redhat.com>
src/mds/CDir.cc
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/Server.cc

index c4f0713ea26dc912665c09681bb5dd090669acf5..41d3ae40c01e356923f62de8ddc0f4e02a1acfc3 100644 (file)
@@ -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())
index 867e192e990034a7a9ea1cd081bbd1aad00f7a7c..7926da79b8a242ab752334b3204533bc5fd66015 100644 (file)
@@ -8942,6 +8942,12 @@ void MDCache::eval_stray(CDentry *dn, bool delay)
          return;  // not until some snaps are deleted.
        }
       }
+      if (in->has_dirfrags()) {
+       list<CDir*> ls;
+       in->get_nested_dirfrags(ls);
+       for (list<CDir*>::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<CDir*> ls;
-    diri->get_nested_dirfrags(ls);
-    for (list<CDir*>::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;
index 0151675f0931c169a9a219e576e439565b1e7c8c..b1459cb97b94e5fd3be744fb29dfe72f5a4a6a74 100644 (file)
@@ -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);
 
index e31da938a0e54ae81382589036597da5cef6ac52..0ef3fea243e2f1bd07a9e1582f46675c86aee905 100644 (file)
@@ -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)