]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: do not try fragmenting or exporting a quiesced directory 57059/head
authorPatrick Donnelly <pdonnell@redhat.com>
Tue, 23 Apr 2024 18:33:14 +0000 (14:33 -0400)
committerPatrick Donnelly <pdonnell@redhat.com>
Mon, 29 Apr 2024 21:08:39 +0000 (17:08 -0400)
And handle inode becoming quiesced after op is created.

Fixes: https://tracker.ceph.com/issues/65603
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
src/mds/MDCache.cc
src/mds/Migrator.cc

index c818a6071e02dd03e6de91b435874105a0259197..0b733b18882af83e920492371db91decef8d2431 100644 (file)
@@ -11685,6 +11685,10 @@ bool MDCache::can_fragment(CInode *diri, const std::vector<CDir*>& dirs)
     dout(7) << "can_fragment: i won't fragment mdsdir or .ceph" << dendl;
     return false;
   }
+  if (diri->is_quiesced()) {
+    dout(7) << "can_fragment: directory inode is quiesced" << dendl;
+    return false;
+  }
 
   for (const auto& dir : dirs) {
     if (dir->scrub_is_in_progress()) {
@@ -12087,6 +12091,16 @@ void MDCache::dispatch_fragment_dir(const MDRequestRef& mdr)
     mdr->aborted = true;
 
   if (!(mdr->locking_state & MutationImpl::ALL_LOCKED)) {
+    /* If quiescelock cannot be wrlocked, we cannot block with tree frozen.
+     * Otherwise, this can create deadlock where some quiesce_inode requests
+     * (on inodes in the dirfrag) are blocked on a frozen tree and the
+     * fragment_dir request is blocked on the queiscelock for the directory
+     * inode's quiescelock.
+     */
+    if (!mdr->is_wrlocked(&diri->quiescelock) && !diri->quiescelock.can_wrlock()) {
+      mdr->aborted = true;
+    }
+
     if (!mdr->aborted) {
       MutationImpl::LockOpVec lov;
       lov.add_wrlock(&diri->dirfragtreelock);
@@ -12104,7 +12118,8 @@ void MDCache::dispatch_fragment_dir(const MDRequestRef& mdr)
   }
 
   if (mdr->aborted) {
-    dout(10) << " can't auth_pin " << *diri << ", requeuing dir "
+    dout(10) << " can't auth_pin or acquire quiescelock on "
+             << *diri << ", requeuing dir "
             << info.dirs.front()->dirfrag() << dendl;
     if (info.bits > 0)
       mds->balancer->queue_split(info.dirs.front(), false);
index abb6dc4397b3268d98c205c573fc397a46d73917..5f84468f394185ee3420d11e4f255a43f96efc9f 100644 (file)
@@ -804,6 +804,9 @@ void Migrator::export_dir(CDir *dir, mds_rank_t dest)
              && parent->get_parent_dir()->ino() != MDS_INO_MDSDIR(dest)) {
     dout(7) << "Cannot export to mds." << dest << " " << *dir << ": in stray directory" << dendl;
     return;
+  } else if (dir->inode->is_quiesced()) {
+    dout(7) << "Cannot export to mds." << dest << " " << *dir << ": is quiesced" << dendl;
+    return;
   }
 
   if (unlikely(g_conf()->mds_thrash_exports)) {
@@ -1006,6 +1009,7 @@ public:
 void Migrator::dispatch_export_dir(const MDRequestRef& mdr, int count)
 {
   CDir *dir = mdr->more()->export_dir;
+  auto* diri = dir->get_inode();
   dout(7) << *mdr << " " << *dir << dendl;
 
   map<CDir*,export_state_t>::iterator it = export_state.find(dir);
@@ -1051,6 +1055,18 @@ void Migrator::dispatch_export_dir(const MDRequestRef& mdr, int count)
 
   // locks?
   if (!(mdr->locking_state & MutationImpl::ALL_LOCKED)) {
+    /* If quiescelock cannot be wrlocked, we cannot block with tree frozen.
+     * Otherwise, this can create deadlock where some quiesce_inode requests
+     * (on inodes in the dirfrag) are blocked on a frozen tree and the
+     * fragment_dir request is blocked on the queiscelock for the directory
+     * inode's quiescelock.
+     */
+    if (!mdr->is_wrlocked(&diri->quiescelock) && !diri->quiescelock.can_wrlock()) {
+      mdr->aborted = true;
+      export_try_cancel(dir);
+      return;
+    }
+
     MutationImpl::LockOpVec lov;
     // If auth MDS of the subtree root inode is neither the exporter MDS
     // nor the importer MDS and it gathers subtree root's fragstat/neststat