From: Kotresh HR Date: Thu, 20 Feb 2025 11:20:31 +0000 (+0530) Subject: mds: Handle referent remote similar to remote X-Git-Tag: v20.3.0~377^2~39 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=1e5fca1582295c9c89ee4afc1d0406cf17940704;p=ceph.git mds: Handle referent remote similar to remote In multiple places in the code, the referent remote needs to be handled similar to remote e.g rstats and dirfrags check etc. This patch adds the check in all the places so the existing functionality doesn't break. The changes are done in the following functions. CDir::encode_lock_state CDir::check_rstats CDir::adjust_dentry_lru CDir::steal_dentry CDir::verify_fragstat ScrubStack::scrub_dirfrag Migrator::maybe_split_export Server::reply_client_request Server::build_snap_diff MDCache::journal_cow_dentry MDCache::path_traverse MDCache::get_dentry_inode MDCache::_open_remote_dentry_finish MDCache::repair_dirfrag_stats_work Fixes: https://tracker.ceph.com/issues/54205 Signed-off-by: Kotresh HR --- diff --git a/src/mds/CDentry.cc b/src/mds/CDentry.cc index 555fe090a8737..4a432c5f2a24a 100644 --- a/src/mds/CDentry.cc +++ b/src/mds/CDentry.cc @@ -494,7 +494,7 @@ void CDentry::encode_lock_state(int type, bufferlist& bl) encode(c, bl); encode(linkage.get_inode()->ino(), bl); } - else if (linkage.is_remote()) { + else if (linkage.is_remote() || linkage.is_referent_remote()) { c = 2; encode(c, bl); encode(linkage.get_remote_ino(), bl); diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index d117507b861ca..a4827086257aa 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -250,7 +250,7 @@ bool CDir::check_rstats(bool scrub) frag_info.nsubdirs++; else frag_info.nfiles++; - } else if (dnl->is_remote()) + } else if (dnl->is_remote() || dnl->is_referent_remote()) frag_info.nfiles++; } @@ -343,7 +343,7 @@ void CDir::adjust_dentry_lru(CDentry *dn) bool bottom_lru; if (dn->get_linkage()->is_primary()) { bottom_lru = !is_auth() && inode->is_stray(); - } else if (dn->get_linkage()->is_remote()) { + } else if (dn->get_linkage()->is_remote() || dn->get_linkage()->is_referent_remote()) { //TODO Is this right for referent remote? bottom_lru = false; } else { bottom_lru = !is_auth(); @@ -1007,7 +1007,7 @@ void CDir::steal_dentry(CDentry *dn) // move dirty inode rstat to new dirfrag if (in->is_dirty_rstat()) dirty_rstat_inodes.push_back(&in->dirty_rstat_item); - } else if (dn->get_linkage()->is_remote()) { + } else if (dn->get_linkage()->is_remote() || dn->get_linkage()->is_referent_remote()) { if (dn->get_linkage()->get_remote_d_type() == DT_DIR) _fnode->fragstat.nsubdirs++; else @@ -3488,7 +3488,7 @@ void CDir::verify_fragstat() else c.nfiles++; } - if (dn->is_remote()) { + if (dn->is_remote() || dn->is_referent_remote()) { if (dn->get_remote_d_type() == DT_DIR) c.nsubdirs++; else diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 65f4b83f8889a..08cbbc2ccaa49 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -1665,7 +1665,14 @@ void MDCache::journal_cow_dentry(MutationImpl *mut, EMetaBlob *metablob, dn->first = dir_follows+1; if (realm->has_snaps_in_range(oldfirst, dir_follows)) { CDir *dir = dn->dir; - // TODO: What does this mean for referent inode ?? Passing nullptr for now. + /* TODO: No need to cow referent inode. So just the remote dentry is prepared, + * journalled and added to dirty_cow_dentries list. But when the journal is + * replayed. How does this play out ? Test this out. + */ + if (mds->mdsmap->allow_referent_inodes()) { + dout(10) << __func__ << " lookout-1 - Adding dentry as remote for journal when referent inode feature is enabled !!! " + << " dentry " << *dn << " first " << oldfirst << " last " << dir_follows << dendl; + } CDentry *olddn = dir->add_remote_dentry(dn->get_name(), nullptr, in->ino(), in->d_type(), dn->alternate_name, oldfirst, dir_follows); dout(10) << " olddn " << *olddn << dendl; ceph_assert(dir->is_projected()); @@ -1751,8 +1758,15 @@ void MDCache::journal_cow_dentry(MutationImpl *mut, EMetaBlob *metablob, metablob->add_primary_dentry(olddn, 0, true, false, false, need_snapflush); mut->add_cow_dentry(olddn); } else { - ceph_assert(dnl->is_remote()); - //No need to journal referent inode for cow + ceph_assert(dnl->is_remote() || dnl->is_referent_remote()); + /* TODO: No need to cow referent inode. So just the remote dentry is prepared, + * journalled and added to dirty_cow_dentries list. But when the journal is + * replayed. How does this play out ? Test this out. + */ + if (mds->mdsmap->allow_referent_inodes()) { + dout(10) << __func__ << " lookout-2 - Adding dentry as remote for journal when referent inode feature is enabled !!! " + << " dentry " << *dn << " first " << oldfirst << " last " << follows << dendl; + } CDentry *olddn = dir->add_remote_dentry(dn->get_name(), nullptr, dnl->get_remote_ino(), dnl->get_remote_d_type(), dn->alternate_name, oldfirst, follows); dout(10) << " olddn " << *olddn << dendl; @@ -8568,7 +8582,7 @@ int MDCache::path_traverse(const MDRequestRef& mdr, MDSContextFactory& cf, // do we have inode? CInode *in = dnl->get_inode(); if (!in) { - ceph_assert(dnl->is_remote()); + ceph_assert(dnl->is_remote() || dnl->is_referent_remote()); // do i have it? in = get_inode(dnl->get_remote_ino()); if (in) { @@ -8857,11 +8871,19 @@ CInode *MDCache::get_dentry_inode(CDentry *dn, const MDRequestRef& mdr, bool pro if (dnl->is_primary()) return dnl->inode; - ceph_assert(dnl->is_remote()); + ceph_assert(dnl->is_remote() || dnl->is_referent_remote()); CInode *in = get_inode(dnl->get_remote_ino()); if (in) { - dout(7) << "get_dentry_inode linking in remote in " << *in << dendl; - dn->link_remote(dnl, in); + CInode *ref_in = dnl->get_referent_inode(); + if (dnl->is_referent_remote()) + ceph_assert(ref_in); + if (ref_in) { + dout(7) << __func__ << " linking in referent remote in " << *in << "referent " << *ref_in << dendl; + dn->link_remote(dnl, in, ref_in); + } else { + dout(7) << __func__ << " linking in remote in " << *in << dendl; + dn->link_remote(dnl, in); + } return in; } else { dout(10) << "get_dentry_inode on remote dn, opening inode for " << *dn << dendl; @@ -8900,7 +8922,7 @@ void MDCache::_open_remote_dentry_finish(CDentry *dn, inodeno_t ino, MDSContext { if (r < 0) { CDentry::linkage_t *dnl = dn->get_projected_linkage(); - if (dnl->is_remote() && dnl->get_remote_ino() == ino) { + if ((dnl->is_remote() || dnl->is_referent_remote()) && dnl->get_remote_ino() == ino) { dout(0) << "open_remote_dentry_finish bad remote dentry " << *dn << dendl; dn->state_set(CDentry::STATE_BADREMOTEINO); @@ -13452,7 +13474,7 @@ void MDCache::repair_dirfrag_stats_work(const MDRequestRef& mdr) frag_info.nsubdirs++; else frag_info.nfiles++; - } else if (dnl->is_remote()) + } else if (dnl->is_remote() || dnl->is_referent_remote()) frag_info.nfiles++; } diff --git a/src/mds/Migrator.cc b/src/mds/Migrator.cc index 82950a07c576a..2d182b4aecdfb 100644 --- a/src/mds/Migrator.cc +++ b/src/mds/Migrator.cc @@ -935,7 +935,7 @@ void Migrator::maybe_split_export(CDir* dir, uint64_t max_size, bool null_okay, dirfrag_size += null_size; continue; } - if (dn->get_linkage()->is_remote()) { + if (dn->get_linkage()->is_remote() || dn->get_linkage()->is_referent_remote()) { dirfrag_size += remote_size; continue; } diff --git a/src/mds/ScrubStack.cc b/src/mds/ScrubStack.cc index cc84a1866ef26..a0d168b023bd6 100644 --- a/src/mds/ScrubStack.cc +++ b/src/mds/ScrubStack.cc @@ -521,7 +521,7 @@ void ScrubStack::scrub_dirfrag(CDir *dir, bool *done) } if (dnl->is_primary()) { _enqueue(dnl->get_inode(), header, false); - } else if (dnl->is_remote()) { + } else if (dnl->is_remote() || dnl->is_referent_remote()) { // TODO: check remote linkage } } diff --git a/src/mds/Server.cc b/src/mds/Server.cc index a77ca844afb0d..2ea3559731aa3 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -2423,7 +2423,7 @@ void Server::reply_client_request(const MDRequestRef& mdr, const ref_tget_projected_linkage()->is_remote()) { + (tracedn->get_projected_linkage()->is_remote() || tracedn->get_projected_linkage()->is_referent_remote())) { mdcache->eval_remote(tracedn); } } @@ -12058,7 +12058,7 @@ bool Server::build_snap_diff( // remote link? // better for the MDS to do the work, if we think the client will stat any of these files. - if (dnl->is_remote() && !in) { + if ((dnl->is_remote() || dnl->is_referent_remote()) && !in) { in = mdcache->get_inode(dnl->get_remote_ino()); dout(20) << __func__ << " remote in: " << *in << " ino " << std::hex << dnl->get_remote_ino() << std::dec << dendl; if (in) {