]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: handle partly purged directory
authorYan, Zheng <zyan@redhat.com>
Wed, 29 Jun 2016 09:15:01 +0000 (17:15 +0800)
committerYan, Zheng <zyan@redhat.com>
Wed, 20 Jul 2016 02:36:16 +0000 (10:36 +0800)
For a snapshoted direcotry whose snaprealm parents are being opened,
MDS does not know if the directory is purgeable. So MDS can't skip
committing dirfrags of the directory. But if the direcotry is purgeale,
some dirfrags could have already been deleted during MDS failover.
Committing them could return -ENOENT.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
(cherry picked from commit bc50e0309280c08c3ca79dfa5514ac3a15f81a23)

src/mds/CDir.cc
src/mds/CInode.cc
src/mds/CInode.h
src/mds/StrayManager.cc

index d99c896f795270a912f36a088fb7f5f4b8e29c08..fcae684f677fd3d1e4d6b48a27d84c9ca69477e9 100644 (file)
@@ -2229,11 +2229,19 @@ void CDir::_commit(version_t want, int op_prio)
 void CDir::_committed(int r, version_t v)
 {
   if (r < 0) {
-    dout(1) << "commit error " << r << " v " << v << dendl;
-    cache->mds->clog->error() << "failed to commit dir " << dirfrag() << " object,"
-                             << " errno " << r << "\n";
-    cache->mds->handle_write_error(r);
-    return;
+    // the directory could be partly purged during MDS failover
+    if (r == -ENOENT && committed_version == 0 &&
+       inode->inode.nlink == 0 && inode->snaprealm) {
+      inode->state_set(CInode::STATE_MISSINGOBJS);
+      r = 0;
+    }
+    if (r < 0) {
+      dout(1) << "commit error " << r << " v " << v << dendl;
+      cache->mds->clog->error() << "failed to commit dir " << dirfrag() << " object,"
+                               << " errno " << r << "\n";
+      cache->mds->handle_write_error(r);
+      return;
+    }
   }
 
   dout(10) << "_committed v " << v << " on " << *this << dendl;
index 3242355ed0c0d684f160f3fb96b0c03d32926c6b..d94e0e2fb0804ff083d71cca6057b785cc015088 100644 (file)
@@ -143,6 +143,7 @@ ostream& operator<<(ostream& out, const CInode& in)
   if (in.state_test(CInode::STATE_NEEDSRECOVER)) out << " needsrecover";
   if (in.state_test(CInode::STATE_RECOVERING)) out << " recovering";
   if (in.state_test(CInode::STATE_DIRTYPARENT)) out << " dirtyparent";
+  if (in.state_test(CInode::STATE_MISSINGOBJS)) out << " missingobjs";
   if (in.is_freezing_inode()) out << " FREEZING=" << in.auth_pin_freeze_allowance;
   if (in.is_frozen_inode()) out << " FROZEN";
   if (in.is_frozen_auth_pin()) out << " FROZEN_AUTHPIN";
@@ -4095,6 +4096,8 @@ void CInode::dump(Formatter *f) const
     f->dump_string("state", "dirtypool");
   if (state_test(STATE_ORPHAN))
     f->dump_string("state", "orphan");
+  if (state_test(STATE_MISSINGOBJS))
+    f->dump_string("state", "missingobjs");
   f->close_section();
 
   f->open_array_section("client_caps");
index 4181191341e20d2ba0fa72ed0b61b684695cc63b..3404d9189c16d34bd03f4433073283ef61431721 100644 (file)
@@ -217,6 +217,7 @@ public:
   static const int STATE_FROZENAUTHPIN = (1<<17);
   static const int STATE_DIRTYPOOL =   (1<<18);
   static const int STATE_REPAIRSTATS = (1<<19);
+  static const int STATE_MISSINGOBJS = (1<<20);
   // orphan inode needs notification of releasing reference
   static const int STATE_ORPHAN =      STATE_NOTIFYREF;
 
index e6f495926239051541c4c1c408cbf90109a043b7..38e7f11b1e248db5e66642f4ea689b19fcb38a73 100644 (file)
@@ -564,7 +564,12 @@ bool StrayManager::__eval_stray(CDentry *dn, bool delay)
     if (in->is_dir()) {
       if (in->snaprealm && in->snaprealm->has_past_parents()) {
        dout(20) << "  directory has past parents "
-          << in->snaprealm->srnode.past_parents << dendl;
+                << in->snaprealm->srnode.past_parents << dendl;
+       if (in->state_test(CInode::STATE_MISSINGOBJS)) {
+         mds->clog->error() << "previous attempt at committing dirfrag of ino "
+                            << in->ino() << " has failed, missing object\n";
+         mds->handle_write_error(-ENOENT);
+       }
        return false;  // not until some snaps are deleted.
       }