]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: drop dirty dentries in deleted directory
authorYan, Zheng <zyan@redhat.com>
Wed, 3 Dec 2014 07:32:33 +0000 (15:32 +0800)
committerYan, Zheng <zyan@redhat.com>
Fri, 5 Dec 2014 00:56:54 +0000 (08:56 +0800)
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 <zyan@redhat.com>
src/mds/CDir.cc
src/mds/CDir.h
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/Server.cc

index ec270769dbed6fb1b19ec0042b7143768f1cceef..5234f710da8c9b5d7d46a98e8781183b7a1e9e4b 100644 (file)
@@ -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)
index 4617f5573d732f7f283eb157f617b8b8d676fb61..00e0b470461b30086d25f0102c6b8c500d92cb40 100644 (file)
@@ -360,6 +360,7 @@ private:
   void purge_stale_snap_data(const std::set<snapid_t>& snaps);
 public:
   void touch_dentries_bottom();
+  void try_remove_dentries_for_stray();
   bool try_trim_snap_dentry(CDentry *dn, const std::set<snapid_t>& snaps);
 
 
index 067f360182bcc4c4aa3d9327ad095a8a0d2553f7..b5339ba0a7e7403196c6ac2fba5c37222dcd31ea 100644 (file)
@@ -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<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 e0fdd4dc91bbc87f51ff1b1bd8d279a0b8d90c34..e42564092d30d121776def2e91a992fe84aabe1e 100644 (file)
@@ -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);
 
index f8c211a11e47ed8b58abd4bcbb82105fb2597c2e..5644711b0fb6a9e2dbaab7d5c68d17aa91eed3b2 100644 (file)
@@ -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)