]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: properly trim log segments after scrub repairs something 21664/head
authorYan, Zheng <zyan@redhat.com>
Thu, 26 Apr 2018 07:50:39 +0000 (15:50 +0800)
committerYan, Zheng <zyan@redhat.com>
Thu, 26 Apr 2018 08:14:30 +0000 (16:14 +0800)
Before calling MDLog::trim_all(), we need to make sure mdlog get flushed
Otherwise, there can be zero expiring log segments. This can cause
MDSGatherBuilder to malfunction. (MDSGatherBuilder::activate() does not
execute empty MDSGatherBuilder's finish context)

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
http://tracker.ceph.com/issues/23880

src/mds/MDCache.cc

index 6803eeadee2ff23714bf4ac173f0880091f8cb2a..7ce2ec02f4b0eb1a61062ad319c474ebcb54c0d4 100644 (file)
@@ -12308,36 +12308,40 @@ void MDCache::enqueue_scrub_work(MDRequestRef& mdr)
   // If the scrub did some repair, then flush the journal at the end of
   // the scrub.  Otherwise in the case of e.g. rewriting a backtrace
   // the on disk state will still look damaged.
-  auto expiry_fin = new FunctionContext([this, header, fin](int r){
-      if (header->get_repaired()) {
-        dout(4) << "Flushing journal because scrub did some repairs" << dendl;
-        mds->mdlog->start_new_segment();
-        mds->mdlog->trim_all();
-        if (fin) {
-          MDSGatherBuilder expiry_gather(g_ceph_context);
-          const std::set<LogSegment*> &expiring_segments = mds->mdlog->get_expiring_segments();
-          for (std::set<LogSegment*>::const_iterator i = expiring_segments.begin();
-               i != expiring_segments.end(); ++i) {
-            (*i)->wait_for_expiry(expiry_gather.new_sub());
-          }
-          expiry_gather.set_finisher(new MDSInternalContextWrapper(mds, fin));
-          expiry_gather.activate();
-        }
-      } else {
-        if (fin) {
-          fin->complete(r);
-        }
+  auto scrub_finish = new FunctionContext([this, header, fin](int r){
+    if (!header->get_repaired()) {
+      if (fin)
+        fin->complete(r);
+      return;
+    }
+
+    auto flush_finish = new FunctionContext([this, fin](int r){
+      dout(4) << "Expiring log segments because scrub did some repairs" << dendl;
+      mds->mdlog->trim_all();
+
+      if (fin) {
+       MDSGatherBuilder gather(g_ceph_context);
+       auto& expiring_segments = mds->mdlog->get_expiring_segments();
+       for (auto logseg : expiring_segments)
+         logseg->wait_for_expiry(gather.new_sub());
+       assert(gather.has_subs());
+       gather.set_finisher(new MDSInternalContextWrapper(mds, fin));
+       gather.activate();
       }
+    });
+
+    dout(4) << "Flushing journal because scrub did some repairs" << dendl;
+    mds->mdlog->start_new_segment();
+    mds->mdlog->flush();
+    mds->mdlog->wait_for_safe(new MDSInternalContextWrapper(mds, flush_finish));
   });
 
   if (!header->get_recursive()) {
     mds->scrubstack->enqueue_inode_top(in, header,
-                                      new MDSInternalContextWrapper(mds,
-                                         expiry_fin));
+                                      new MDSInternalContextWrapper(mds, scrub_finish));
   } else {
     mds->scrubstack->enqueue_inode_bottom(in, header, 
-                                      new MDSInternalContextWrapper(mds,
-                                         expiry_fin));
+                                      new MDSInternalContextWrapper(mds, scrub_finish));
   }
 
   mds->server->respond_to_request(mdr, 0);