From 67925a3a1c8acd912a57d3c85e7075d4b5e49496 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Tue, 23 Apr 2024 14:33:14 -0400 Subject: [PATCH] mds: do not try fragmenting or exporting a quiesced directory And handle inode becoming quiesced after op is created. Fixes: https://tracker.ceph.com/issues/65603 Signed-off-by: Patrick Donnelly --- src/mds/MDCache.cc | 17 ++++++++++++++++- src/mds/Migrator.cc | 16 ++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index c818a6071e0..0b733b18882 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -11685,6 +11685,10 @@ bool MDCache::can_fragment(CInode *diri, const std::vector& 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); diff --git a/src/mds/Migrator.cc b/src/mds/Migrator.cc index abb6dc4397b..5f84468f394 100644 --- a/src/mds/Migrator.cc +++ b/src/mds/Migrator.cc @@ -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::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 -- 2.39.5