[PATCH 5/5] ceph: narrow mdsc->mutex scope in replay_unsafe_requests
From: Xiubo Li via B4 Relay
Date: Mon Jul 13 2026 - 05:48:23 EST
From: Xiubo Li <xiubo.li@xxxxxxxxx>
__send_request() is lockless so holding mdsc->mutex across the
replay loop only serializes the list iteration itself. Collect
the unsafe list entries under the mutex, then replay them without
it. The old-request tree walk uses xa_for_each() which is
internally locked.
Signed-off-by: Xiubo Li <xiubo.li@xxxxxxxxx>
---
fs/ceph/mds_client.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index ef54d19ace2a..6c5a8c651d3e 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -4673,12 +4673,25 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc,
{
struct ceph_mds_request *req, *nreq;
unsigned long idx;
+ LIST_HEAD(replay_list);
doutc(mdsc->fsc->client, "mds%d\n", session->s_mds);
+ /* collect unsafe requests under the mutex */
mutex_lock(&mdsc->mutex);
- list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item)
+ list_for_each_entry_safe(req, nreq, &session->s_unsafe,
+ r_unsafe_item) {
+ ceph_mdsc_get_request(req);
+ list_move(&req->r_unsafe_item, &replay_list);
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ /* replay unsafe requests — __send_request is lockless */
+ list_for_each_entry_safe(req, nreq, &replay_list, r_unsafe_item) {
__send_request(session, req, true);
+ list_del_init(&req->r_unsafe_item);
+ ceph_mdsc_put_request(req);
+ }
/*
* also re-send old requests when MDS enters reconnect stage. So that MDS
@@ -4699,7 +4712,6 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc,
__send_request(session, req, true);
}
- mutex_unlock(&mdsc->mutex);
}
static int send_reconnect_partial(struct ceph_reconnect_state *recon_state)
--
2.53.0