]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds/quiesce: overdrive an export if it hasn't frozen the tree yet
authorLeonid Usov <leonid.usov@ibm.com>
Mon, 20 May 2024 16:17:04 +0000 (19:17 +0300)
committerLeonid Usov <leonid.usov@ibm.com>
Sun, 26 May 2024 08:33:52 +0000 (11:33 +0300)
Just like with the fragmenting, we should abort an ongoing export
if a quiesce is attempted for the directory.

To minimize the stress for the system, we only allow the abort
if the export hasn't yet managed to freeze the tree. If that is the case,
then quiesce will have to wait for the export to finish.

Fixes: https://tracker.ceph.com/issues/66123
Signed-off-by: Leonid Usov <leonid.usov@ibm.com>
src/mds/MDCache.cc
src/mds/Migrator.cc
src/mds/Migrator.h

index a545daded17b4af6a44cbb37c3948a5319a11667..65ffac60889b03e4d48b006902cf095a6785dc73 100644 (file)
@@ -13758,6 +13758,7 @@ void MDCache::dispatch_quiesce_inode(const MDRequestRef& mdr)
       dout(25) << " iterating " << *dir << dendl;
       // overdrive syncrhonously since we aren't yet on the waiting list
       quiesce_overdrive_fragmenting(dir, false);
+      migrator->quiesce_overdrive_export(dir);
       for (auto& [dnk, dn] : *dir) {
         dout(25) << " evaluating (" << dnk << ", " << *dn << ")" << dendl;
         auto* in = dn->get_projected_inode();
@@ -13795,6 +13796,7 @@ void MDCache::dispatch_quiesce_inode(const MDRequestRef& mdr)
       }
     }
     if (gather.has_subs()) {
+      mdr->mark_event("quiescing children");
       dout(20) << __func__ << ": waiting for sub-ops to gather" << dendl;
       gather.activate();
       return;
index 3600f78c572b651c30aba6d30d42f76d1fb7abc3..cb77282e384432fe7292c71069984f658412dfd7 100644 (file)
@@ -242,6 +242,20 @@ void Migrator::find_stale_export_freeze()
   }
 }
 
+void Migrator::quiesce_overdrive_export(CDir *dir) {
+  map<CDir*, export_state_t>::iterator it = export_state.find(dir);
+  if (it == export_state.end()) {
+    return;
+  }
+  auto state = it->second.state;
+  if (state <= EXPORT_FREEZING) {
+    dout(10) << "will try to cancel in state: (" << state << ") " << get_export_statename(state) << dendl;
+    export_try_cancel(dir, true);
+  } else {
+    dout(10) << "won't cancel in state: (" << state << ") " << get_export_statename(state) << dendl;
+  }
+}
+
 void Migrator::export_try_cancel(CDir *dir, bool notify_peer)
 {
   dout(10) << *dir << dendl;
@@ -1229,13 +1243,18 @@ void Migrator::handle_export_discover_ack(const cref_t<MExportDirDiscoverAck> &m
     ceph_assert(it->second.state == EXPORT_DISCOVERING);
 
     if (m->is_success()) {
+      // move to freezing the subtree
+      it->second.state = EXPORT_FREEZING;
+      auto&& mdr = boost::static_pointer_cast<MDRequestImpl>(std::move(it->second.mut));
+      ceph_assert(!it->second.mut); // should have been moved out of
+
       // release locks to avoid deadlock
-      MDRequestRef mdr = static_cast<MDRequestImpl*>(it->second.mut.get());
       ceph_assert(mdr);
+      // We should only call request_finish after we changed the state.
+      // Other requests may run as part of the finish here, so we want them
+      // to see this export in the updated state.
       mdcache->request_finish(mdr);
-      it->second.mut.reset();
-      // freeze the subtree
-      it->second.state = EXPORT_FREEZING;
+
       dir->auth_unpin(this);
       ceph_assert(g_conf()->mds_kill_export_at != 3);
 
@@ -2388,7 +2407,11 @@ void Migrator::handle_export_cancel(const cref_t<MExportDirCancel> &m)
   dirfrag_t df = m->get_dirfrag();
   map<dirfrag_t,import_state_t>::iterator it = import_state.find(df);
   if (it == import_state.end()) {
-    ceph_abort_msg("got export_cancel in weird state");
+    // don't assert here: we could NACK a discovery and also
+    // receive an async cancel.
+    // In general, it shouldn't be fatal error to receive a cancel
+    // for an opration we don't know about.
+    dout(3) << "got export_cancel for an unknown fragment " << df << dendl;
   } else if (it->second.state == IMPORT_DISCOVERING) {
     import_reverse_discovering(df);
   } else if (it->second.state == IMPORT_DISCOVERED) {
index 53bf99fb639c1e9844fe3f856db47b9a99674280..d6e599c06a995aa9c2cf18a258817d32350060b9 100644 (file)
@@ -182,6 +182,7 @@ public:
   void handle_mds_failure_or_stop(mds_rank_t who);
 
   void audit();
+  void quiesce_overdrive_export(CDir *dir);
 
   // -- import/export --
   // exporter