]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: drop locks and retry when lock set changes 53243/head
authorPatrick Donnelly <pdonnell@redhat.com>
Mon, 17 Jul 2023 20:10:59 +0000 (16:10 -0400)
committerPatrick Donnelly <pdonnell@redhat.com>
Thu, 31 Aug 2023 12:35:18 +0000 (08:35 -0400)
An optimization was added to avoid an unnecessary gather on the inode
filelock when the client can safely get the file size without also
getting issued the requested caps. However, if a retry of getattr
is necessary, this conditional inclusion of the inode filelock
can cause lock-order violations resulting in deadlock.

So, if we've already acquired some of the inode's locks then we must
drop locks and retry.

Fixes: https://tracker.ceph.com/issues/62052
Fixes: c822b3e2573578c288d170d1031672b74e02dced
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
(cherry picked from commit b5719ac32fe6431131842d62ffaf7101c03e9bac)

src/mds/Server.cc

index 82f2a2e5e6587d2a79085a53586d1e1a3bf8d93b..188c7728416d25d3262415f7237fb3c0be09e7d8 100644 (file)
@@ -4071,6 +4071,24 @@ void Server::handle_client_getattr(MDRequestRef& mdr, bool is_lookup)
     } else if (ref->filelock.is_stable() ||
               ref->filelock.get_num_wrlocks() > 0 ||
               !ref->filelock.can_read(mdr->get_client())) {
+      /* Since we're taking advantage of an optimization here:
+       *
+       * We cannot suddenly, due to a changing condition, add this filelock as
+       * it can cause lock-order deadlocks. In this case, that condition is the
+       * lock state changes between request retries. If that happens, we need
+       * to check if we've acquired the other locks in this vector. If we have,
+       * then we need to drop those locks and retry.
+       */
+      if (mdr->is_rdlocked(&ref->linklock) ||
+          mdr->is_rdlocked(&ref->authlock) ||
+          mdr->is_rdlocked(&ref->xattrlock)) {
+        /* start over */
+        dout(20) << " dropping locks and restarting request because filelock state change" << dendl;
+       mds->locker->drop_locks(mdr.get());
+       mdr->drop_local_auth_pins();
+       mds->queue_waiter(new C_MDS_RetryRequest(mdcache, mdr));
+        return;
+      }
       lov.add_rdlock(&ref->filelock);
       mdr->locking_state &= ~MutationImpl::ALL_LOCKED;
     }