From f94c8327facbb313a720f2fcfb013a4f9b00a8e5 Mon Sep 17 00:00:00 2001 From: Kotresh HR Date: Tue, 25 Feb 2025 16:22:07 +0530 Subject: [PATCH] multi-mds/unlink: Remove referent inode on unlink On the unlink of the secondary hardlink with the referent inode, remove the referent inode. This patch takes care of multi-mds scenario where the primary/real inode auth is a different mds than the secondary dentry auth (also the referent inode auth). Fixes: https://tracker.ceph.com/issues/54205 Signed-off-by: Kotresh HR --- src/mds/Server.cc | 72 ++++++++++++++++++++++++++++++++++++++--------- src/mds/Server.h | 4 +-- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/mds/Server.cc b/src/mds/Server.cc index dc497655df0cf..0b955005bdd91 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -7710,7 +7710,7 @@ void Server::handle_client_link(const MDRequestRef& mdr) if (targeti->is_auth()) _link_local(mdr, destdn, targeti, target_realm); else - _link_remote(mdr, true, destdn, targeti); + _link_remote(mdr, true, destdn, targeti, nullptr); mds->balancer->maybe_fragment(dir, false); } @@ -7849,24 +7849,26 @@ class C_MDS_link_remote_finish : public ServerLogContext { CDentry *dn; CInode *targeti; CInode *referenti; + CDentry *straydn; version_t dpv; public: - C_MDS_link_remote_finish(Server *s, const MDRequestRef& r, bool i, CDentry *d, CInode *ti, CInode *ri) : - ServerLogContext(s, r), inc(i), dn(d), targeti(ti), referenti(ri), + C_MDS_link_remote_finish(Server *s, const MDRequestRef& r, bool i, CDentry *d, CInode *ti, CInode *ri, CDentry *sd) : + ServerLogContext(s, r), inc(i), dn(d), targeti(ti), referenti(ri), straydn(sd), dpv(d->get_projected_version()) {} void finish(int r) override { ceph_assert(r == 0); - server->_link_remote_finish(mdr, inc, dn, targeti, referenti, dpv); + server->_link_remote_finish(mdr, inc, dn, targeti, referenti, straydn, dpv); } }; -void Server::_link_remote(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti) +void Server::_link_remote(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti, CDentry *straydn) { dout(10) << "_link_remote " << (inc ? "link ":"unlink ") << *dn << " to " << *targeti << dendl; CInode *newi = nullptr; + CDentry::linkage_t *dnl = dn->get_projected_linkage(); // create referent inode. Don't re-create on retry if (mds->mdsmap->allow_referent_inodes() && inc) { @@ -7957,20 +7959,49 @@ void Server::_link_remote(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode dn->push_projected_linkage(targeti->ino(), targeti->d_type()); } } else { - dn->pre_dirty(); - mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, -1); - mdcache->journal_cow_dentry(mdr.get(), &le->metablob, dn); - le->metablob.add_null_dentry(dn, true); - dn->push_projected_linkage(); + if (dnl->is_referent_remote()) { + ceph_assert(straydn); + CInode *ref_in = dnl->get_referent_inode(); + ceph_assert(ref_in->is_auth()); + + straydn->push_projected_linkage(ref_in); + dn->pre_dirty(); // the unlinked dentry + + // referent remote link - to purge the referent inode created + auto pri = ref_in->project_inode(mdr); + { + std::string t; + dn->make_path_string(t, true); + pri.inode->stray_prior_path = std::move(t); + } + pri.inode->version = ref_in->pre_dirty(); + // Purge enqueue requires inode to be primary and nlink to be 0 + pri.inode->nlink = 0; + ref_in->state_set(CInode::STATE_ORPHAN); + mdcache->predirty_journal_parents(mdr, &le->metablob, ref_in, straydn->get_dir(), PREDIRTY_PRIMARY|PREDIRTY_DIR, 1); + pri.inode->update_backtrace(); + le->metablob.add_primary_dentry(straydn, ref_in, true, true); + + mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, -1); + mdcache->journal_cow_dentry(mdr.get(), &le->metablob, dn); + le->metablob.add_null_dentry(dn, true); + dn->push_projected_linkage(); + } else { + dn->pre_dirty(); + mdcache->predirty_journal_parents(mdr, &le->metablob, targeti, dn->get_dir(), PREDIRTY_DIR, -1); + mdcache->journal_cow_dentry(mdr.get(), &le->metablob, dn); + le->metablob.add_null_dentry(dn, true); + dn->push_projected_linkage(); + } } journal_and_reply(mdr, (inc ? targeti : nullptr), dn, le, - new C_MDS_link_remote_finish(this, mdr, inc, dn, targeti, newi)); + new C_MDS_link_remote_finish(this, mdr, inc, dn, targeti, newi, straydn)); } void Server::_link_remote_finish(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti, CInode *referenti, - version_t dpv) + CDentry *straydn, version_t dpv) { dout(10) << "_link_remote_finish " << (inc ? "link ":"unlink ") @@ -7998,6 +8029,13 @@ void Server::_link_remote_finish(const MDRequestRef& mdr, bool inc, dn->get_dir()->unlink_inode(dn); dn->pop_projected_linkage(); dn->mark_dirty(dn->get_projected_version(), mdr->ls); // dirty old dentry + + // relink as stray? + if (straydn) { + dout(20) << __func__ << " referent - straydn is " << *straydn << dendl; + straydn->pop_projected_linkage(); + mdcache->touch_dentry_bottom(straydn); + } } mdr->apply(); @@ -8018,6 +8056,12 @@ void Server::_link_remote_finish(const MDRequestRef& mdr, bool inc, if (!inc) // removing a new dn? dn->get_dir()->try_remove_unlinked_dn(dn); + + if (straydn && !straydn->get_projected_linkage()->is_null()) { + // Tip off the MDCache that this dentry is a stray that + // might be elegible for purge. + mdcache->notify_stray(straydn); + } } @@ -8532,8 +8576,8 @@ void Server::handle_client_unlink(const MDRequestRef& mdr) mds->locker->create_lock_cache(mdr, diri); // ok! - if (dnl->is_remote() && !dnl->get_inode()->is_auth()) - _link_remote(mdr, false, dn, dnl->get_inode()); + if ((dnl->is_remote() || dnl->is_referent_remote()) && !dnl->get_inode()->is_auth()) + _link_remote(mdr, false, dn, dnl->get_inode(), straydn); else _unlink_local(mdr, dn, straydn); } diff --git a/src/mds/Server.h b/src/mds/Server.h index 5f3f63d7ca9bb..3e9da2606ae11 100644 --- a/src/mds/Server.h +++ b/src/mds/Server.h @@ -282,9 +282,9 @@ public: void _link_local_finish(const MDRequestRef& mdr, CDentry *dn, CInode *targeti, CInode *referenti, version_t, version_t, bool); - void _link_remote(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti); + void _link_remote(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti, CDentry *straydn); void _link_remote_finish(const MDRequestRef& mdr, bool inc, CDentry *dn, CInode *targeti, - CInode *referenti, version_t); + CInode *referenti, CDentry *sd, version_t); void handle_peer_link_prep(const MDRequestRef& mdr); void _logged_peer_link(const MDRequestRef& mdr, CInode *targeti, bool adjust_realm); -- 2.39.5