From 919bb50289a16d19573fa555007d04f7c2a7c035 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Mon, 17 Jul 2023 16:10:59 -0400 Subject: [PATCH] mds: drop locks and retry when lock set changes 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 (cherry picked from commit b5719ac32fe6431131842d62ffaf7101c03e9bac) --- src/mds/Server.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 82f2a2e5e6587..188c7728416d2 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -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; }