]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds/rename: Handle existing destdn referent remote
authorKotresh HR <khiremat@redhat.com>
Wed, 26 Feb 2025 08:41:34 +0000 (14:11 +0530)
committerKotresh HR <khiremat@redhat.com>
Tue, 4 Mar 2025 06:20:47 +0000 (11:50 +0530)
This can also happen with out the linkmerge case.
A different file can be renamed to the existing
referent remote dentry. This patch handles the same.
Also, as part of it, it removes the corresponding
referent inode from the list of primary/real inode.

Fixes: https://tracker.ceph.com/issues/54205
Signed-off-by: Kotresh HR <khiremat@redhat.com>
src/mds/Server.cc

index 541158853e71f8f5010c91bf3a2c5d183a945cf4..044ab1e00c43ac741b20822c0a7c1b9d29b8b768 100644 (file)
@@ -9919,6 +9919,33 @@ void Server::_rename_prepare(const MDRequestRef& mdr,
        pi.inode->version = oldin->pre_dirty();
         tpi = pi.inode.get();
       }
+    } else if (destdnl->is_referent_remote()) { //non-linkmerge case
+      CInode *oldrefi = destdnl->get_referent_inode();
+      ceph_assert(straydn && oldrefi);  // moving to straydn.
+      dout(10) << " destdnl is referent. oldrefi " << *oldrefi << dendl;
+
+      // nlink-- targeti
+      if (oldin->is_auth()) {
+       auto pi = oldin->project_inode(mdr);
+       pi.inode->version = oldin->pre_dirty();
+        tpi = pi.inode.get();
+
+        // Remove referent inode from primary if destdnl exists and is referent
+        tpi->remove_referent_ino(oldrefi->ino());
+        dout(20) << "_rename_prepare destdnl exists and is referent, referent_inodes " << std::hex
+                 << tpi->get_referent_inodes() << " referent ino removed " << oldrefi->ino() << dendl;
+      }
+
+      // link--, and move referent inode
+      if (destdn->is_auth()) {
+       auto pi= oldrefi->project_inode(mdr); //project_snaprealm
+       pi.inode->version = straydn->pre_dirty(pi.inode->version);
+       //backtrace updation is not required
+        trpi = pi.inode.get();
+        trpi->nlink = 0;
+        oldrefi->state_set(CInode::STATE_ORPHAN);
+      }
+      straydn->push_projected_linkage(oldrefi);
     }
   } else if (linkmerge && destdnl->is_referent_remote()) {
       CInode *oldrefi = destdnl->get_referent_inode();
@@ -10142,6 +10169,23 @@ void Server::_rename_prepare(const MDRequestRef& mdr,
        mdcache->journal_cow_dentry(mdr.get(), metablob, oldin_pdn);
        metablob->add_primary_dentry(oldin_pdn, oldin, true);
       }
+      // referent inode stuff
+      if (destdnl->is_referent_remote()) { //non-linkmerge case
+        CInode *oldrefi = destdnl->get_referent_inode();
+        ceph_assert(straydn);
+        ceph_assert(oldrefi);
+        if (destdn->is_auth()) {
+          // No snapshot on referent inode - Ignoring snaprealm projection
+          // Updating first is required here ? Mostly not required, keeping
+          // it for now.
+          straydn->first = mdcache->get_global_snaprealm()->get_newest_seq() + 1;
+          metablob->add_primary_dentry(straydn, oldrefi, true, true);
+        } else if (force_journal_stray) {
+         dout(10) << " forced journaling referent straydn " << *straydn << dendl;
+         metablob->add_dir_context(straydn->get_dir());
+         metablob->add_primary_dentry(straydn, oldrefi, true);
+        }
+      }
     }
   } else if (linkmerge && destdnl->is_referent_remote()) {
     CInode *oldrefi = destdnl->get_referent_inode();
@@ -10320,8 +10364,31 @@ void Server::_rename_apply(const MDRequestRef& mdr, CDentry *srcdn, CDentry *des
        oldin->pop_and_dirty_projected_inode(mdr->ls, mdr);
 
       mdcache->touch_dentry_bottom(straydn);  // drop dn as quickly as possible.
-    } else if (destdnl->is_remote()) {
-      destdn->get_dir()->unlink_inode(destdn, false);
+    } else if (destdnl->is_remote() || destdnl->is_referent_remote()) {
+      if (destdnl->is_referent_remote()) { //non-linkmerge case
+        ceph_assert(straydn);
+        dout(10) << __func__ << " linkmerge:no referent straydn is " << *straydn << dendl;
+
+        // No snapshots on referent inodes - skipping snaprealm related stuff
+        // on referent inode
+       CInode *oldrefin = destdnl->get_referent_inode();
+       ceph_assert(oldrefin);
+
+        destdn->get_dir()->unlink_inode(destdn, false);
+
+        straydn->pop_projected_linkage();
+        if (mdr->is_peer() && !mdr->more()->peer_update_journaled)
+         ceph_assert(!straydn->is_projected()); // no other projected
+
+        if (destdn->is_auth())
+         oldrefin->pop_and_dirty_projected_inode(mdr->ls, mdr);
+
+        mdcache->touch_dentry_bottom(straydn);  // drop dn as quickly as possible.
+      } else if (destdnl->is_remote()) {
+        // This is already done for referent above.
+        destdn->get_dir()->unlink_inode(destdn, false);
+      }
+
       if (oldin->is_auth()) {
        oldin->pop_and_dirty_projected_inode(mdr->ls, mdr);
       } else if (mdr->peer_request) {