linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] mm: introduce 'encoded' page pointers with embedded extra bits
@ 2022-11-09 20:30 Linus Torvalds
  2022-11-09 20:30 ` [PATCH 2/4] mm: teach release_pages() to take an array of encoded page pointers too Linus Torvalds
                   ` (3 more replies)
  0 siblings, 4 replies; 17+ messages in thread
From: Linus Torvalds @ 2022-11-09 20:30 UTC (permalink / raw)
  To: Hugh Dickins, Johannes Weiner, Andrew Morton
  Cc: linux-kernel, linux-mm, Alexander Gordeev

We already have this notion in parts of the MM code (see the mlock code
with the LRU_PAGE and NEW_PAGE bits), but I'm going to introduce a new
case, and I refuse to do the same thing we've done before where we just
put bits in the raw pointer and say it's still a normal pointer.

So this introduces a 'struct encoded_page' pointer that cannot be used
for anything else than to encode a real page pointer and a couple of
extra bits in the low bits.  That way the compiler can trivially track
the state of the pointer and you just explicitly encode and decode the
extra bits.

Note that this makes the alignment of 'struct page' explicit even for
the case where CONFIG_HAVE_ALIGNED_STRUCT_PAGE is not set.  That is
entirely redundant in almost all cases, since the page structure already
contains several word-sized entries.

However, on m68k, the alignment of even 32-bit data is just 16 bits, and
as such in theory the alignment of 'struct page' could be too.  So let's
just make it very very explicit that the alignment needs to be at least
32 bits, giving us a guarantee of two unused low bits in the pointer.

Now, in practice, our page struct array is aligned much more than that
anyway, even on m68k, and our existing code in mm/mlock.c obviously
already depended on that.  But since the whole point of this change is
to be careful about the type system when hiding extra bits in the
pointer, let's also be explicit about the assumptions we make.

NOTE! This is being very careful in another way too: it has a build-time
assertion that the 'flags' added to the page pointer actually fit in the
two bits.  That means that this helper must be inlined, and can only be
used in contexts where the compiler can statically determine that the
value fits in the available bits.

Link: https://lore.kernel.org/all/Y2tKixpO4RO6DgW5@tuxmaker.boeblingen.de.ibm.com/
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 include/linux/mm_types.h | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 500e536796ca..0a38fcb08d85 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -67,7 +67,7 @@ struct mem_cgroup;
 #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
 #define _struct_page_alignment	__aligned(2 * sizeof(unsigned long))
 #else
-#define _struct_page_alignment
+#define _struct_page_alignment	__aligned(sizeof(unsigned long))
 #endif
 
 struct page {
@@ -241,6 +241,38 @@ struct page {
 #endif
 } _struct_page_alignment;
 
+/**
+ * struct encoded_page - a nonexistent type marking this pointer
+ *
+ * An 'encoded_page' pointer is a pointer to a regular 'struct page', but
+ * with the low bits of the pointer indicating extra context-dependent
+ * information. Not super-common, but happens in mmu_gather and mlock
+ * handling, and this acts as a type system check on that use.
+ *
+ * We only really have two guaranteed bits in general, although you could
+ * play with 'struct page' alignment (see CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
+ * for more.
+ *
+ * Use the supplied helper functions to endcode/decode the pointer and bits.
+ */
+struct encoded_page;
+#define ENCODE_PAGE_BITS 3ul
+static __always_inline struct encoded_page *encode_page(struct page *page, unsigned long flags)
+{
+	BUILD_BUG_ON(flags > ENCODE_PAGE_BITS);
+	return (struct encoded_page *)(flags | (unsigned long)page);
+}
+
+static inline unsigned long encoded_page_flags(struct encoded_page *page)
+{
+	return ENCODE_PAGE_BITS & (unsigned long)page;
+}
+
+static inline struct page *encoded_page_ptr(struct encoded_page *page)
+{
+	return (struct page *)(~ENCODE_PAGE_BITS & (unsigned long)page);
+}
+
 /**
  * struct folio - Represents a contiguous set of bytes.
  * @flags: Identical to the page flags.
-- 
2.38.1.284.gfd9468d787



^ permalink raw reply related	[flat|nested] 17+ messages in thread
* Re: mm: delay rmap removal until after TLB flush
@ 2022-11-07 23:47 Linus Torvalds
  2022-11-08 19:41 ` [PATCH 2/4] mm: teach release_pages() to take an array of encoded page pointers too Linus Torvalds
  0 siblings, 1 reply; 17+ messages in thread
From: Linus Torvalds @ 2022-11-07 23:47 UTC (permalink / raw)
  To: Johannes Weiner
  Cc: Hugh Dickins, Stephen Rothwell, Alexander Gordeev, Peter Zijlstra,
	Will Deacon, Aneesh Kumar, Nick Piggin, Heiko Carstens,
	Vasily Gorbik, Christian Borntraeger, Sven Schnelle, Nadav Amit,
	Jann Horn, John Hubbard, X86 ML, Matthew Wilcox, Andrew Morton,
	kernel list, Linux-MM, Andrea Arcangeli, Kirill A . Shutemov,
	Joerg Roedel, Uros Bizjak, Alistair Popple, linux-arch

On Mon, Nov 7, 2022 at 12:29 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> That said, if always doing the rmap removal under the page table lock
> means that that memcg lock can just be deleted in that whole path, I
> will certainly bow to _that_ simplification instead, and just handle
> the dirty pages after the TLB flush but before the page table drop.

Ok, so I think I have a fairly clean way to do this.

Let me try to make that series look reasonable, although it might be
until tomorrow. I'll need to massage my mess into not just prettier
code, but a sane history.

               Linus


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2022-11-16 17:58 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-09 20:30 [PATCH 1/4] mm: introduce 'encoded' page pointers with embedded extra bits Linus Torvalds
2022-11-09 20:30 ` [PATCH 2/4] mm: teach release_pages() to take an array of encoded page pointers too Linus Torvalds
2022-11-16  9:24   ` David Hildenbrand
2022-11-09 20:30 ` [PATCH 3/4] mm: mmu_gather: prepare to gather encoded page pointers with flags Linus Torvalds
2022-11-09 20:30 ` [PATCH 4/4] mm: delay page_remove_rmap() until after the TLB has been flushed Linus Torvalds
2022-11-09 20:48   ` Linus Torvalds
2022-11-09 21:04     ` Linus Torvalds
2022-11-16  7:47       ` Alexander Gordeev
2022-11-16  7:49         ` mm: mmu_gather: do not expose delayed_rmap flag Alexander Gordeev
2022-11-16 17:45           ` Linus Torvalds
2022-11-16  7:50         ` mm: mmu_gather: do not define delayed_rmap if not used Alexander Gordeev
2022-11-16 17:52           ` Linus Torvalds
2022-11-16  7:52         ` [PATCH 3/4] mm: mmu_gather: turn delayed rmap macros into inlines Alexander Gordeev
2022-11-16  7:55         ` [PATCH 4/4] mm: mmu_gather: rename tlb_delay_rmap() function Alexander Gordeev
2022-11-16 17:39         ` [PATCH 4/4] mm: delay page_remove_rmap() until after the TLB has been flushed Linus Torvalds
2022-11-16  9:15 ` [PATCH 1/4] mm: introduce 'encoded' page pointers with embedded extra bits David Hildenbrand
  -- strict thread matches above, loose matches on Subject: below --
2022-11-07 23:47 mm: delay rmap removal until after TLB flush Linus Torvalds
2022-11-08 19:41 ` [PATCH 2/4] mm: teach release_pages() to take an array of encoded page pointers too Linus Torvalds

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).