]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mds/MDSDaemon: unlock `mds_lock` while shutting down Beacon and others
authorMax Kellermann <max.kellermann@ionos.com>
Fri, 11 Oct 2024 22:35:13 +0000 (00:35 +0200)
committerVenky Shankar <vshankar@redhat.com>
Thu, 7 Aug 2025 10:29:02 +0000 (15:59 +0530)
This fixes a deadlock bug during MDS shutdown:

- the "signal_handler" thread receives the shutdown signal and invokes
  MDSDaemon::suicide() while holding `mds_lock`

- MDSDaemon::suicide() invokes Beacon::send_and_wait() while still
  holding `mds_lock`

- meanwhile, all "ms_dispatch" threads get stuck waiting for
  `mds_lock`, for example in MDCache::upkeep_main() or
  MDSDaemon::ms_dispatch2()

- Beacon::send_and_wait() waits for a `MSG_MDS_BEACON` packet to be
  dispatched (via `cvar` with a timeout)

At this point, even if a `MSG_MDS_BEACON` packet is received by one of
the worker threads, they will put it in the `DispatchQueue`, but no
dispatcher thread will be able to handle it because they are all
stuck.  The cvar.wait_for() call in Beacon::send_and_wait() will
therefore time out and the `MSG_MDS_BEACON` will never be processed.

The proper solution is to unlock `mds_lock` to avoid the dispatchers
from getting stuck.  And in general, we should be holding a lock
strictly only when it is needed and never do blocking calls while
holding a lock.

Fixes: https://tracker.ceph.com/issues/68760
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
(cherry picked from commit c0fedb52fa61cd4a847f5be7eb66629f9b7b6ab7)

src/mds/MDSDaemon.cc

index 60fb3a874229789ef405ff55de4a1b0b85c59005..a06810621bc07d714f0e5b2c4eac83ebc881e288 100644 (file)
@@ -899,6 +899,13 @@ void MDSDaemon::suicide()
   // to wait for us to go laggy. Only do this if we're actually in the MDSMap,
   // because otherwise the MDSMonitor will drop our message.
   beacon.set_want_state(*mdsmap, MDSMap::STATE_DNE);
+
+  /* Unlock the mds_lock while waiting for beacon ACK to avoid a
+   * deadlock with the dispatcher thread which may try to acquire
+   * mds_lock, preventing it from receiving the beacon ACK.
+   */
+  mds_lock.unlock();
+
   if (!mdsmap->is_dne_gid(mds_gid_t(monc->get_global_id()))) {
     beacon.send_and_wait(1);
   }
@@ -907,6 +914,8 @@ void MDSDaemon::suicide()
   if (mgrc.is_initialized())
     mgrc.shutdown();
 
+  mds_lock.lock();
+
   if (mds_rank) {
     mds_rank->shutdown();
   } else {