From: Patrick Donnelly Date: Sat, 2 Mar 2024 03:01:48 +0000 (-0500) Subject: mds: block import discover when parent directory inode is quiesced X-Git-Tag: v20.0.0~2328^2~12 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=1ec6817cc082b379fba86bcd0a73ff950d7d1152;p=ceph.git 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 --- diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index cd08d798dfba8..d62d93e16fd88 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 963784ced0382..7ac4f95627889 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 d6b554c77681c..abb6dc4397b32 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.