From 780f244382b155dd6d6b38de5d04bb38e9bc30b1 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Fri, 1 Mar 2024 22:01:48 -0500 Subject: [PATCH] mds: block import discover when parent directory inode is quiesced This is to prevent two racing ranks quiescing some root from exporting a tree under a completely quiesced directory (inode). The state of that imported tree may take time to quiesce and cause the root to be QUIESCED before all inodes under it are actually quiesced. If a dirfrag to be imported is discovered before the parent is quiesced, then the quiesce traversal will issue a quiesce_inode op normally for parent which will attempt to authpin the parent. That will block if the export is still in-progress (causing quiesce to wait for the export to finish or abort). Signed-off-by: Patrick Donnelly (cherry picked from commit 1ec6817cc082b379fba86bcd0a73ff950d7d1152) --- src/mds/MDCache.cc | 35 ++++++++++++++++++++++++----------- src/mds/MDCache.h | 1 + src/mds/Migrator.cc | 21 +++++++++++++++------ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index cd08d798dfb..d62d93e16fd 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -8293,6 +8293,7 @@ int MDCache::path_traverse(const MDRequestRef& mdr, MDSContextFactory& cf, bool rdlock_path = (flags & MDS_TRAVERSE_RDLOCK_PATH); bool xlock_dentry = (flags & MDS_TRAVERSE_XLOCK_DENTRY); bool rdlock_authlock = (flags & MDS_TRAVERSE_RDLOCK_AUTHLOCK); + bool forimport = (flags & MDS_TRAVERSE_IMPORT); if (forward) ceph_assert(mdr); // forward requires a request @@ -8403,11 +8404,17 @@ int MDCache::path_traverse(const MDRequestRef& mdr, MDSContextFactory& cf, curdir = cur->get_or_open_dirfrag(this, fg); } else { // discover? - dout(10) << "traverse: need dirfrag " << fg << ", doing discover from " << *cur << dendl; - discover_path(cur, snapid, path.postfixpath(depth), cf.build(), - path_locked); - if (mds->logger) mds->logger->inc(l_mds_traverse_discover); - return 1; + if (forimport && cur->is_quiesced()) { + /* block discover for import */ + dout(5) << __func__ << ": blocking discover due to quiesced parent: " << *cur << dendl; + return -CEPHFS_EAGAIN; + } else { + dout(10) << "traverse: need dirfrag " << fg << ", doing discover from " << *cur << dendl; + discover_path(cur, snapid, path.postfixpath(depth), cf.build(), + path_locked); + if (mds->logger) mds->logger->inc(l_mds_traverse_discover); + return 1; + } } } ceph_assert(curdir); @@ -8641,12 +8648,18 @@ int MDCache::path_traverse(const MDRequestRef& mdr, MDSContextFactory& cf, } if (discover) { - dout(7) << "traverse: discover from " << path[depth] << " from " << *curdir << dendl; - discover_path(curdir, snapid, path.postfixpath(depth), cf.build(), - path_locked); - if (mds->logger) mds->logger->inc(l_mds_traverse_discover); - return 1; - } + if (forimport && cur->is_quiesced()) { + /* block discover for import */ + dout(5) << __func__ << ": blocking discover due to quiesced parent: " << *cur << dendl; + return -CEPHFS_EAGAIN; + } else { + dout(7) << "traverse: discover from " << path[depth] << " from " << *curdir << dendl; + discover_path(curdir, snapid, path.postfixpath(depth), cf.build(), + path_locked); + if (mds->logger) mds->logger->inc(l_mds_traverse_discover); + return 1; + } + } if (forward) { // forward dout(7) << "traverse: not auth for " << path << " in " << *curdir << dendl; diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index 963784ced03..7ac4f956278 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -133,6 +133,7 @@ static const int MDS_TRAVERSE_XLOCK_DENTRY = (1 << 8); static const int MDS_TRAVERSE_RDLOCK_AUTHLOCK = (1 << 9); static const int MDS_TRAVERSE_CHECK_LOCKCACHE = (1 << 10); static const int MDS_TRAVERSE_WANT_INODE = (1 << 11); +static const int MDS_TRAVERSE_IMPORT = (1 << 12); // flags for predirty_journal_parents() diff --git a/src/mds/Migrator.cc b/src/mds/Migrator.cc index d6b554c7768..abb6dc4397b 100644 --- a/src/mds/Migrator.cc +++ b/src/mds/Migrator.cc @@ -1223,7 +1223,7 @@ void Migrator::handle_export_discover_ack(const cref_t &m ceph_assert(g_conf()->mds_kill_export_at != 3); } else { - dout(7) << "peer failed to discover (not active?), canceling" << dendl; + dout(7) << "peer failed to discover (not active or quiesced), canceling" << dendl; export_try_cancel(dir, false); } } @@ -2309,13 +2309,22 @@ void Migrator::handle_export_discover(const cref_t &m, bool filepath fpath(m->get_path()); vector trace; MDRequestRef null_ref; - int r = mdcache->path_traverse(null_ref, cf, fpath, - MDS_TRAVERSE_DISCOVER | MDS_TRAVERSE_PATH_LOCKED, - &trace); + static constexpr int flags = 0 + | MDS_TRAVERSE_DISCOVER + | MDS_TRAVERSE_PATH_LOCKED + | MDS_TRAVERSE_IMPORT; + int r = mdcache->path_traverse(null_ref, cf, fpath, flags, &trace); if (r > 0) return; if (r < 0) { - dout(7) << "failed to discover or not dir " << m->get_path() << ", NAK" << dendl; - ceph_abort(); // this shouldn't happen if the auth pins its path properly!!!! + if (r == -CEPHFS_EAGAIN) { + dout(5) << "blocking import during quiesce" << dendl; + import_reverse_discovering(df); + mds->send_message_mds(make_message(df, m->get_tid(), false), from); + return; + } else { + dout(7) << "failed to discover or not dir " << m->get_path() << ", NAK" << dendl; + ceph_abort(); // this shouldn't happen if the auth pins its path properly!!!! + } } ceph_abort(); // this shouldn't happen; the get_inode above would have succeeded. -- 2.39.5