Re: [RFC PATCH] mm: dump_page: print total mapcount for compound page

From: Yang Shi
Date: Fri May 28 2021 - 15:04:10 EST


On Fri, May 28, 2021 at 11:26 AM John Hubbard <jhubbard@xxxxxxxxxx> wrote:
>
> On 5/28/21 10:54 AM, Yang Shi wrote:
> > The total mapcount is a useful information for debugging, but we can't
> > call total_mapcount() directly since it calls some assertions which may
> > be triggered as commit 6dc5ea16c86f ("mm,
> > dump_page: do not crash with bad compound_mapcount()") met.
> >
> > We could implement yet another implementation for dump_page() but
> > it has the limitation when individual mapcount of subpages is corrupted.
> >
> > Actually the total mapcount could be decoded from refcount, pincount and
> > compound mapcount although it may be not very precise due to some
> > transient references.
>
> If the mapcount calculation were in a separate routine, *and* if something
> else in addition to dump_page() used it, then I'd be interested in
> calling it from dump_page().

There is. The total_mapcount() is used by mm code. But as I mentioned
in the commit log and that discussion email, it is not safe to call it
directly in dump_page() path.

>
> But, just adding a calculation glob like this is not a good idea. If
> the reader really needs the calculation, then that person can, as you
> say, work it out from the other information.
>
> Debug and dump routines are actually supposed to remain fairly simple,
> so that they themselves do not end up with bugs, or stale assumptions
> (which this calculation is very much susceptible to). This goes in the
> wrong direction.
>
> So best to just not do this, IMHO.
>
> thanks,
> --
> John Hubbard
> NVIDIA
>
> >
> > Signed-off-by: Yang Shi <shy828301@xxxxxxxxx>
> > ---
> > I think we are on the same page that the total mapcount is useful
> > information and it would be ideal to print this information when dumpping
> > page if possible. But how to implement it safely seems controversial.
> > Some ideas and potential problems have been discussed by
> > https://lore.kernel.org/linux-mm/alpine.LSU.2.11.2105261733110.16920@eggly.anvils/.
> >
> > So I prepared this patch to show a possible approach to get some
> > feedback. The same thing could be decoded by the reader of page dump
> > as well by using the same formula used by this patch. However it sounds
> > more convenient to have kernel do the math.
> >
> > mm/debug.c | 35 +++++++++++++++++++++++++++++------
> > 1 file changed, 29 insertions(+), 6 deletions(-)
> >
> > diff --git a/mm/debug.c b/mm/debug.c
> > index e73fe0a8ec3d..129efcfcaf79 100644
> > --- a/mm/debug.c
> > +++ b/mm/debug.c
> > @@ -54,8 +54,13 @@ static void __dump_page(struct page *page)
> > * inaccuracy here due to racing.
> > */
> > bool page_cma = is_migrate_cma_page(page);
> > - int mapcount;
> > + int mapcount, total_mapcount;
> > + int nr;
> > + int refcount;
> > + int pincount = 0;
> > + int comp_mapcnt;
> > char *type = "";
> > + bool is_slab = PageSlab(head);
> >
> > if (page < head || (page >= head + MAX_ORDER_NR_PAGES)) {
> > /*
> > @@ -82,22 +87,40 @@ static void __dump_page(struct page *page)
> > * page->_mapcount space in struct page is used by sl[aou]b pages to
> > * encode own info.
> > */
> > - mapcount = PageSlab(head) ? 0 : page_mapcount(page);
> > + mapcount = is_slab ? 0 : page_mapcount(page);
> > +
> > + refcount = page_ref_count(head);
> >
> > pr_warn("page:%p refcount:%d mapcount:%d mapping:%p index:%#lx pfn:%#lx\n",
> > - page, page_ref_count(head), mapcount, mapping,
> > + page, refcount, mapcount, mapping,
> > page_to_pgoff(page), page_to_pfn(page));
> > if (compound) {
> > + comp_mapcnt = head_compound_mapcount(head);
> > if (hpage_pincount_available(page)) {
> > + pincount = head_compound_pincount(head);
> > pr_warn("head:%p order:%u compound_mapcount:%d compound_pincount:%d\n",
> > head, compound_order(head),
> > - head_compound_mapcount(head),
> > - head_compound_pincount(head));
> > + comp_mapcnt, pincount);
> > } else {
> > pr_warn("head:%p order:%u compound_mapcount:%d\n",
> > head, compound_order(head),
> > - head_compound_mapcount(head));
> > + comp_mapcnt);
> > + }
> > +
> > + nr = compound_nr(head);
> > + if (is_slab)
> > + total_mapcount = 0;
> > + else if (PageHuge(head))
> > + total_mapcount = comp_mapcnt;
> > + else {
> > + if (mapping) {
> > + if (!PageAnon(head))
> > + nr = nr * (comp_mapcnt + 1) - comp_mapcnt;
> > + } else
> > + nr = 0;
> > + total_mapcount = refcount - pincount - nr;
> > }
> > + pr_warn("total_mapcount(estimated):%d\n", total_mapcount);
> > }
> >
> > #ifdef CONFIG_MEMCG
> >
>