Re: [PATCH 1/1] libceph: fix memory leak for messages allocated with CEPH_MSG_DATA_PAGES

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 10, 2020 at 11:15 AM Roman Penyaev <rpenyaev@xxxxxxx> wrote:
>
> On 2020-03-10 11:03, Ilya Dryomov wrote:
> > On Tue, Mar 10, 2020 at 10:09 AM Roman Penyaev <rpenyaev@xxxxxxx>
> > wrote:
> >>
> >> OSD client allocates a message with a page vector for OSD_MAP,
> >> OSD_BACKOFF
> >> and WATCH_NOTIFY message types (see alloc_msg_with_page_vector()
> >> caller),
> >> but pages vector release is never called.
> >>
> >> Signed-off-by: Roman Penyaev <rpenyaev@xxxxxxx>
> >> Cc: Ilya Dryomov <idryomov@xxxxxxxxx>
> >> Cc: Jeff Layton <jlayton@xxxxxxxxxx>
> >> Cc: Sage Weil <sage@xxxxxxxxxx>
> >> Cc: ceph-devel@xxxxxxxxxxxxxxx
> >> ---
> >>  net/ceph/messenger.c | 9 ++++++++-
> >>  1 file changed, 8 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
> >> index 5b4bd8261002..28cbd55ec2e3 100644
> >> --- a/net/ceph/messenger.c
> >> +++ b/net/ceph/messenger.c
> >> @@ -3248,8 +3248,15 @@ static struct ceph_msg_data
> >> *ceph_msg_data_add(struct ceph_msg *msg)
> >>
> >>  static void ceph_msg_data_destroy(struct ceph_msg_data *data)
> >>  {
> >> -       if (data->type == CEPH_MSG_DATA_PAGELIST)
> >> +       if (data->type == CEPH_MSG_DATA_PAGES) {
> >> +               int num_pages;
> >> +
> >> +               num_pages = calc_pages_for(data->alignment,
> >> +                                          data->length);
> >> +               ceph_release_page_vector(data->pages, num_pages);
> >> +       } else if (data->type == CEPH_MSG_DATA_PAGELIST) {
> >>                 ceph_pagelist_release(data->pagelist);
> >> +       }
> >>  }
> >>
> >>  void ceph_msg_data_add_pages(struct ceph_msg *msg, struct page
> >> **pages,
> >
> > Hi Roman,
> >
> > I don't think there is a leak here.
> >
> > osdmap and backoff messages don't have data.
>
> I tried to be symmetric on this path: allocation path
> exists, but there is no deallocation.
>
> > watch_notify message may or may not have data and this is dealt
> > with in handle_watch_notify().  The pages are either released in
> > handle_watch_notify() or transferred to ceph_osdc_notify() through
> > lreq.  The caller of ceph_osdc_notify() is then responsible for
> > them:
> >
> >    * @preply_{pages,len} are initialized both on success and error.
> >    * The caller is responsible for:
> >    *
> >    *     ceph_release_page_vector(...)
> >    */
> >   int ceph_osdc_notify(struct ceph_osd_client *osdc,
>
> Thanks for taking a look. Then there is a rare and unobvious
> leak, please check ceph_con_in_msg_alloc() in messenger.c.
> Message can be allocated for osd client (->alloc_msg) and then
> can be immediately put by the following path:
>
>         if (con->state != CON_STATE_OPEN) {
>                 if (msg)
>                         ceph_msg_put(msg);
>
> (also few lines below where con->in_msg is put)
>
> without reaching the dispatch and set of handle_* functions,
> which you've referred.

Yeah, this one is real, and rather old.  That is why there is a TODO
on top of alloc_msg_with_page_vector():

  /*
   * TODO: switch to a msg-owned pagelist
   */

>
> And seems if the ownership of the ->pages is transferred to
> the handle_watch_notify() and freed there, then it should be
> fixed by having release in one place: here or there.

The problem is that at least at one point CEPH_MSG_DATA_PAGES needed
a reference count -- it couldn't be freed it in one place.  pagelists
are reference counted, but can't be easily swapped in, hence that TODO.

Thanks for reminding me about this.  I'll take a look -- perhaps the
reference count is no longer required and we can get away with a simple
flag.

                Ilya



[Index of Archives]     [CEPH Users]     [Ceph Large]     [Ceph Dev]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux