[PATCH v3 2/3] ceph/mds_client: stop checking a stale MDS map after dropping mutex

From: Max Kellermann

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


check_new_map() drops `mdsc->mutex` in several slow paths. Another
map handler can install a newer map and destroy the map being checked
before the original invocation re-locks the mutex.

Use the `mdsmap->m_epoch` field to identify stale maps.

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

diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 160f23e2edd3..03809328e4aa 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -5782,6 +5782,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
struct ceph_mdsmap *newmap,
struct ceph_mdsmap *oldmap)
{
+ u32 map_epoch = newmap->m_epoch;
int i, j, err;
int oldstate, newstate;
struct ceph_mds_session *s;
@@ -5825,6 +5826,8 @@ static void check_new_map(struct ceph_mds_client *mdsc,
ceph_put_mds_session(s);

mutex_lock(&mdsc->mutex);
+ if (mdsc->mdsmap->m_epoch != map_epoch)
+ return;
kick_requests(mdsc, i);
continue;
}
@@ -5836,6 +5839,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
+ if (mdsc->mdsmap->m_epoch != map_epoch) {
+ mutex_unlock(&s->s_mutex);
+ ceph_put_mds_session(s);
+ return;
+ }
ceph_con_close(&s->s_con);
mutex_unlock(&s->s_mutex);
s->s_state = CEPH_MDS_SESSION_RESTARTING;
@@ -5859,6 +5867,10 @@ static void check_new_map(struct ceph_mds_client *mdsc,
"mds%d reconnect failed: %d\n",
i, rc);
mutex_lock(&mdsc->mutex);
+ if (mdsc->mdsmap->m_epoch != map_epoch) {
+ ceph_put_mds_session(s);
+ return;
+ }
}

/*
@@ -5874,6 +5886,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
+ if (mdsc->mdsmap->m_epoch != map_epoch) {
+ mutex_unlock(&s->s_mutex);
+ ceph_put_mds_session(s);
+ return;
+ }
ceph_kick_flushing_caps(mdsc, s);
mutex_unlock(&s->s_mutex);
wake_up_session_caps(s, RECONNECT);
@@ -5929,6 +5946,8 @@ static void check_new_map(struct ceph_mds_client *mdsc,
i, err);
ceph_put_mds_session(s);
mutex_lock(&mdsc->mutex);
+ if (mdsc->mdsmap->m_epoch != map_epoch)
+ return;
}

for (i = 0; i < newmap->possible_max_rank && i < mdsc->max_sessions; i++) {
--
2.47.3