[PATCH v3 1/3] ceph/mds_client: pin sessions while checking a new MDS map

From: Max Kellermann

Date: Fri Aug 28 2026 - 13:45:58 EST


check_new_map() drops `mdsc->mutex` while it locks a session, prepares
a reconnect, or cleans up caps. A concurrent teardown can unregister
and release a session, invalidating check_new_map()'s local variable
`s`.

Fix this by taking a temporary session reference using
__ceph_lookup_mds_session() instead of accessing the `sessions[]`
array directly.

Signed-off-by: Max Kellermann <max.kellermann@xxxxxxxxx>
---
fs/ceph/mds_client.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 3c692ad02c85..160f23e2edd3 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -5798,9 +5798,9 @@ static void check_new_map(struct ceph_mds_client *mdsc,
}

for (i = 0; i < oldmap->possible_max_rank && i < mdsc->max_sessions; i++) {
- if (!mdsc->sessions[i])
+ s = __ceph_lookup_mds_session(mdsc, i);
+ if (!s)
continue;
- s = mdsc->sessions[i];
oldstate = ceph_mdsmap_get_state(oldmap, i);
newstate = ceph_mdsmap_get_state(newmap, i);

@@ -5813,7 +5813,6 @@ static void check_new_map(struct ceph_mds_client *mdsc,

if (i >= newmap->possible_max_rank) {
/* force close session for stopped mds */
- ceph_get_mds_session(s);
__unregister_session(mdsc, s);
__wake_requests(mdsc, &s->s_waiting);
mutex_unlock(&mdsc->mutex);
@@ -5841,6 +5840,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
mutex_unlock(&s->s_mutex);
s->s_state = CEPH_MDS_SESSION_RESTARTING;
} else if (oldstate == newstate) {
+ ceph_put_mds_session(s);
continue; /* nothing new with this mds */
}

@@ -5878,6 +5878,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
mutex_unlock(&s->s_mutex);
wake_up_session_caps(s, RECONNECT);
}
+ ceph_put_mds_session(s);
}

/*
--
2.47.3