lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAHk-=whCgz0Kh3dGB-razGqgzM=spcO1fcyzD3vQd8PEO-bA0g@mail.gmail.com>
Date: Sat, 23 Nov 2024 12:57:49 -0800
From: Linus Torvalds <torvalds@...ux-foundation.org>
To: John Hubbard <jhubbard@...dia.com>
Cc: David Hildenbrand <david@...hat.com>, Andrew Morton <akpm@...ux-foundation.org>, 
	Matthew Wilcox <willy@...radead.org>, linux-mm@...ck.org, mm-commits@...r.kernel.org, 
	linux-kernel@...r.kernel.org
Subject: Re: [GIT PULL] MM updates for 6.13-rc1

On Sat, 23 Nov 2024 at 12:30, John Hubbard <jhubbard@...dia.com> wrote:
>
> >
> > ... not able to come up with good names though. folio_page0(), folio_first_page(), ... :(
>
> Eh? You're doing great at coming up with good names, IMHO. Either of the
> above would work nicely!
>
> I'll put my vote in for folio_page0(), it's concise and yet crystal clear.

I think all of this is completely missing the point.

The point is that "&folio->page" can be *compared* to a page pointer,
even when "folio" itself is not a valid pointer itself.

Changing

        if (&folio->page == page)

to

        if (folio_page0(folio) == page)

doesn't actually help anything at all. It still makes confused people
who do not understand pointer comparisons "oh, but if 'folio' is
invalid, I can't do 'folio_page0(folio)'".

See the problem, and see how you are not actually _fixing_ the confusion?

The way to hopefully *fix* the confusion is to have the actual
comparison itself inside the helper. Something like a

   static __always_inline bool folio_is_page(struct folio *folio,
struct page *page)
  { return &folio->page == page; }

and maybe even add a comment about how pointer comparisons are valid
even when the pointers are NULL or entirely invalid error pointers.

If you want to be extra fancy, you'd do something like

  union page_or_folio {
        struct page *page;
        struct folio *folio;
  };

  static inline bool folio_match(union page_or_folio a,
                                 union page_or_folio b)
  {
        return a.page == b.page;
  }

which doesn't care about argument ordering, and allows any combination
of folio or page pointers (but unlike a 'void *' argument, accepts
*only* folio or page pointers). So then you can do either
"folio_match(folio, page)" or "folio_match(page, folio)" and they are
the same thing.

Of course, the above does depend on "&folio->page" being effectively a
no-op (ie the page and folio pointers really are bitwise the same, ie
the ->page entry is at offset zero).

Which they are, and which all the FOLIO_MATCH things verify, but it
might be worth clarifying.

Honestly, I feel that we should use that "union page_or_folio" in more
places to avoid duplicating some of the helper functions, when a
function really doesn't care whether it gets a page or a folio. We
have a fair number of unnecessarily duplicated functions, I feel (eg
folio_mapping_flags() vs PageMappingFlags()), and I suspect some of
the "convert to folio" work could have been simplified by having code
that just happily accepts one or the other.

It probably matters less today, though, since a lot of the folio
conversion has been done.

And yes, you can also use _Generic() to automatically handle either
case, and that's particularly useful if you actually want to do
different things for a folio vs a page. For example, you could have a
"size" function that returns PAGE_SIZE for a 'struct page *', but
folio_size() for a 'struct folio *'.

Like the union argument trick, the _Generic() thing can be used to
make conversions easier, when you have functions that simply
JustWork(tm) and DoTheRightThing(tm) regardless of the type, and you
don't necessarily have to convert everything in one go.

              Linus

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ