Re: [PATCH 1/1] libceph: unpublish osdmap before destroying it on stop

Ilya Dryomov <[email protected]> Thu, 23 Jul 2026 20:55:45 +0200
Newsgroups org.kernel.vger.ceph-devel
Message-ID <CAOi1vP_A3aNbj6iTRdtMMa37yfKcRNeGdixd=6OmBRnTa0X0AA@mail.gmail.com>
On Mon, Jul 20, 2026 at 5:49 AM Ren Wei <[email protected]> wrote:
>
> From: Zihan Xi <[email protected]>
>
> osdmap_show() takes osdc->lock for reading and then walks
> osdc->osdmap while formatting the debugfs osdmap file. During client
> teardown, ceph_osdc_stop() closes the OSD state under the write side of
> that lock, drops the lock, and only then destroys osdc->osdmap while the
> pointer is still published.
>
> A concurrent debugfs reader can therefore acquire the read side after the
> stop path has dropped it and traverse an osdmap that is being freed or has
> already been freed.
>
> Take the osdmap pointer out of osdc under the write lock before dropping
> that lock, then destroy the saved pointer after unlocking. This makes the
> write lock wait for any current osdmap_show() reader and makes later
> readers observe a NULL osdmap instead of a freed object. Also make queued
> OSD map messages return after taking the lock if teardown has already
> unpublished the osdmap.
>
> Fixes: 76aa844d5b2f ("ceph: debugfs")
> Cc: [email protected]
> Reported-by: Vega <[email protected]>
> Assisted-by: Codex:gpt-5.4
> Signed-off-by: Zihan Xi <[email protected]>
> Reviewed-by: Ren Wei <[email protected]>
> ---
>  net/ceph/osd_client.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
> index 2ff00070c181..70467eede336 100644
> --- a/net/ceph/osd_client.c
> +++ b/net/ceph/osd_client.c
> @@ -4145,8 +4145,11 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
>         bool pauserd, pausewr;
>         int err;
>
> -       dout("%s have %u\n", __func__, osdc->osdmap->epoch);
>         down_write(&osdc->lock);
> +       if (!osdc->osdmap)
> +               goto out_unlock;
> +
> +       dout("%s have %u\n", __func__, osdc->osdmap->epoch);
>
>         /* verify fsid */
>         ceph_decode_need(&p, end, sizeof(fsid), bad);
> @@ -4238,6 +4241,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
>  bad:
>         pr_err("osdc handle_map corrupt msg\n");
>         ceph_msg_dump(msg);
> +out_unlock:
>         up_write(&osdc->lock);
>  }
>
> @@ -5268,6 +5272,8 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
>
>  void ceph_osdc_stop(struct ceph_osd_client *osdc)
>  {
> +       struct ceph_osdmap *osdmap;
> +
>         destroy_workqueue(osdc->completion_wq);
>         destroy_workqueue(osdc->notify_wq);
>         cancel_delayed_work_sync(&osdc->timeout_work);
> @@ -5279,6 +5285,8 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc)
>                                                 struct ceph_osd, o_node);
>                 close_osd(osd);
>         }
> +       osdmap = osdc->osdmap;
> +       osdc->osdmap = NULL;
>         up_write(&osdc->lock);
>         WARN_ON(refcount_read(&osdc->homeless_osd.o_ref) != 1);
>         osd_cleanup(&osdc->homeless_osd);
> @@ -5290,7 +5298,7 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc)
>         WARN_ON(atomic_read(&osdc->num_requests));
>         WARN_ON(atomic_read(&osdc->num_homeless));
>
> -       ceph_osdmap_destroy(osdc->osdmap);
> +       ceph_osdmap_destroy(osdmap);
>         mempool_destroy(osdc->req_mempool);
>         ceph_msgpool_destroy(&osdc->msgpool_op);
>         ceph_msgpool_destroy(&osdc->msgpool_op_reply);
> --
> 2.43.0

Hi Ren,

I think this is already fixed by another patch that you seem to have
been involved in:

https://lore.kernel.org/ceph-devel/e346902d49608e030177ffb00423e776f4a916ee.1781280238.git.ldy3087146292@gmail.com/

Thanks,

                Ilya