]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: wait the linkmerge/migrate to finish after unlink 50984/head
authorXiubo Li <xiubli@redhat.com>
Tue, 2 Aug 2022 06:19:59 +0000 (14:19 +0800)
committerXiubo Li <xiubli@redhat.com>
Tue, 11 Apr 2023 01:38:46 +0000 (09:38 +0800)
If one inode has more than one link and after one of its dentries
being unlinked it will be moved to stray directory. Before the
linkmerge/migrate finises if a link request comes it will fail
with -EXDEV.

While in non-multiple link case it's also possible that the clients
could pass one invalidate ino, which is still under unlinking.

Just wait the linkmerge/migrate or purge to finish.

https://tracker.ceph.com/issues/56695
Signed-off-by: Xiubo Li <xiubli@redhat.com>
(cherry picked from commit 48f9a8990b402daa0f0f9109bc4b0087c01b33c6)

src/mds/CInode.h
src/mds/Server.cc
src/mds/StrayManager.cc

index a2b034ec647c9061fcbe0d12f60dcdeda05198a2..3f18ab0fe864b199c0dc1f5f973bd77b3feec8d8 100644 (file)
@@ -398,7 +398,8 @@ class CInode : public MDSCacheObject, public InodeStoreBase, public Counter<CIno
   static const uint64_t WAIT_FROZEN      = (1<<1);
   static const uint64_t WAIT_TRUNC       = (1<<2);
   static const uint64_t WAIT_FLOCK       = (1<<3);
-  
+  static const uint64_t WAIT_UNLINK      = (1<<4);
+
   static const uint64_t WAIT_ANY_MASK  = (uint64_t)(-1);
 
   // misc
index fbac61e0870514881fca4b3d76ecf13eae290cb1..eaaec5d7bfd691b0ee32270567b78f9834e5581b 100644 (file)
@@ -7209,6 +7209,13 @@ void Server::handle_client_link(MDRequestRef& mdr)
   if (target_pin != dir->inode &&
       target_realm->get_subvolume_ino() !=
       dir->inode->find_snaprealm()->get_subvolume_ino()) {
+    if (target_pin->is_stray()) {
+      mds->locker->drop_locks(mdr.get());
+      targeti->add_waiter(CInode::WAIT_UNLINK,
+                          new C_MDS_RetryRequest(mdcache, mdr));
+      mdlog->flush();
+      return;
+    }
     dout(7) << "target is in different subvolume, failing..." << dendl;
     respond_to_request(mdr, -CEPHFS_EXDEV);
     return;
@@ -9024,6 +9031,12 @@ void Server::handle_client_rename(MDRequestRef& mdr)
   C_MDS_rename_finish *fin = new C_MDS_rename_finish(this, mdr, srcdn, destdn, straydn);
 
   journal_and_reply(mdr, srci, destdn, le, fin);
+
+  // trigger to flush mdlog in case reintegrating or migrating the stray dn,
+  // because the link requests maybe waiting.
+  if (srcdn->get_dir()->inode->is_stray()) {
+    mdlog->flush();
+  }
   mds->balancer->maybe_fragment(destdn->get_dir(), false);
 }
 
@@ -9624,6 +9637,14 @@ void Server::_rename_apply(MDRequestRef& mdr, CDentry *srcdn, CDentry *destdn, C
 
   srcdn->get_dir()->unlink_inode(srcdn);
 
+  // After the stray dn being unlinked from the corresponding inode in case of
+  // reintegrate_stray/migrate_stray, just wake up the waitiers.
+  MDSContext::vec finished;
+  in->take_waiting(CInode::WAIT_UNLINK, finished);
+  if (!finished.empty()) {
+    mds->queue_waiters(finished);
+  }
+
   // dest
   if (srcdn_was_remote) {
     if (!linkmerge) {
index ab8f0ddb49e260c599dbe508d1aebb61afe145ec..4aae3edead8f1f0c50a15133bb2eaff982230c80 100644 (file)
@@ -281,6 +281,17 @@ void StrayManager::_purge_stray_logged(CDentry *dn, version_t pdv, MutationRef&
     dir->remove_dentry(dn);
   }
 
+  // Once we are here normally the waiter list are mostly empty
+  // but in corner case that the clients pass a invalidate ino,
+  // which maybe under unlinking, the link caller will add the
+  // request to the waiter list. We need try to wake them up
+  // anyway.
+  MDSContext::vec finished;
+  in->take_waiting(CInode::WAIT_UNLINK, finished);
+  if (!finished.empty()) {
+    mds->queue_waiters(finished);
+  }
+
   // drop inode
   inodeno_t ino = in->ino();
   if (in->is_dirty())