Re: [PATCH v4 2/3] ceph: stop checking a stale MDS map after dropping mutex
From: Xiubo Li
Date: Fri Sep 04 2026 - 21:55:25 EST
LGTM.
Reviewed-by: Xiubo Li <xiubo.li@xxxxxxxxx>
On Fri, 4 Sept 2026 at 08:03, Max Kellermann <max.kellermann@xxxxxxxxx> wrote:
>
> 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. Continuing to
> dereference newmap after that results in a use-after-free.
>
> Use the `mdsmap->m_epoch` field to identify stale maps.
>
> Fixes: 2f2dc053404f ("ceph: MDS client")
> Cc: stable@xxxxxxxxxxxxxxx
> 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 d36a114747ae..86d592f06196 100644
> --- a/fs/ceph/mds_client.c
> +++ b/fs/ceph/mds_client.c
> @@ -5844,6 +5844,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;
> @@ -5887,6 +5888,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;
> }
> @@ -5898,6 +5901,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;
> @@ -5921,6 +5929,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;
> + }
> }
>
> /*
> @@ -5936,6 +5948,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);
> @@ -5991,6 +6008,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
>