diff mbox series

[RFC,v2,1/3] mm: Add TAIL_MAPPING_REUSED_MAX

Message ID 20230814184411.330496-2-peterx@redhat.com (mailing list archive)
State New
Headers show
Series mm: Properly document tail pages for a folio | expand

Commit Message

Peter Xu Aug. 14, 2023, 6:44 p.m. UTC
Tail pages have a sanity check on ->mapping fields, not all of them but
only upon index>2.  It's because we reused ->mapping fields of the tail
pages index=0,1 for other things.

Define a macro for "max index of tail pages that got ->mapping field
reused" on top of folio definition, because when we grow folio tail pages
we'd want to boost this too together.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 include/linux/mm_types.h | 9 +++++++++
 mm/huge_memory.c         | 6 +++---
 2 files changed, 12 insertions(+), 3 deletions(-)

Comments

Peter Xu Aug. 14, 2023, 6:52 p.m. UTC | #1
On Mon, Aug 14, 2023 at 02:44:09PM -0400, Peter Xu wrote:
> Tail pages have a sanity check on ->mapping fields, not all of them but
> only upon index>2.  It's because we reused ->mapping fields of the tail
> pages index=0,1 for other things.
> 
> Define a macro for "max index of tail pages that got ->mapping field
> reused" on top of folio definition, because when we grow folio tail pages
> we'd want to boost this too together.
> 
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
>  include/linux/mm_types.h | 9 +++++++++
>  mm/huge_memory.c         | 6 +++---
>  2 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index 291c05cacd48..3f2b0d46f5d6 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -248,6 +248,15 @@ static inline struct page *encoded_page_ptr(struct encoded_page *page)
>  	return (struct page *)(~ENCODE_PAGE_BITS & (unsigned long)page);
>  }
>  
> +/*
> + * This macro defines the maximum tail pages (of a folio) that can have the
> + * page->mapping field reused (offset 12 for 32bits, or 24 for 64bits).
> + *
> + * When the tail page's mapping field reused, it'll be exempted from
> + * ->mapping poisoning and checks.  Also see the macro TAIL_MAPPING.
> + */
> +#define  TAIL_MAPPING_REUSED_MAX  (2)
> +
>  /**
>   * struct folio - Represents a contiguous set of bytes.
>   * @flags: Identical to the page flags.
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 0b709d2c46c6..72f244e16dcb 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2444,9 +2444,9 @@ static void __split_huge_page_tail(struct page *head, int tail,
>  			 (1L << PG_dirty) |
>  			 LRU_GEN_MASK | LRU_REFS_MASK));
>  
> -	/* ->mapping in first and second tail page is replaced by other uses */
> -	VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING,
> -			page_tail);
> +	/* ->mapping in <=TAIL_MAPPING_REUSED_MAX tail pages are reused */
> +	VM_BUG_ON_PAGE(tail > TAIL_MAPPING_REUSED_MAX &&
> +		       page_tail->mapping != TAIL_MAPPING, page_tail);
>  	page_tail->mapping = head->mapping;
>  	page_tail->index = head->index + tail;

I tend to also squash this in when repost:

diff --git a/mm/internal.h b/mm/internal.h
index 02a6fd36f46e..a75df0bd1f89 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -428,7 +428,8 @@ static inline void prep_compound_tail(struct page *head, int tail_idx)
 {
        struct page *p = head + tail_idx;

-       p->mapping = TAIL_MAPPING;
+       if (tail_idx > TAIL_MAPPING_REUSED_MAX)
+               p->mapping = TAIL_MAPPING;
        set_compound_head(p, head);
        set_page_private(p, 0);
 }
Matthew Wilcox Aug. 14, 2023, 7:08 p.m. UTC | #2
On Mon, Aug 14, 2023 at 02:44:09PM -0400, Peter Xu wrote:
> +/*
> + * This macro defines the maximum tail pages (of a folio) that can have the
> + * page->mapping field reused (offset 12 for 32bits, or 24 for 64bits).

No, don't say how many bytes into the structure something is.  It'll
only get out of date.  If somebody needs to know, use pahole.

> + * When the tail page's mapping field reused, it'll be exempted from
> + * ->mapping poisoning and checks.  Also see the macro TAIL_MAPPING.
> + */
> +#define  TAIL_MAPPING_REUSED_MAX  (2)

More importantly, I think this is over-parametrisation.  If you start to
use extra fields in struct folio, just change the code in page_alloc.c
directly.
Peter Xu Aug. 14, 2023, 7:51 p.m. UTC | #3
On Mon, Aug 14, 2023 at 08:08:57PM +0100, Matthew Wilcox wrote:
> On Mon, Aug 14, 2023 at 02:44:09PM -0400, Peter Xu wrote:
> > +/*
> > + * This macro defines the maximum tail pages (of a folio) that can have the
> > + * page->mapping field reused (offset 12 for 32bits, or 24 for 64bits).
> 
> No, don't say how many bytes into the structure something is.  It'll
> only get out of date.  If somebody needs to know, use pahole.

OK.

> 
> > + * When the tail page's mapping field reused, it'll be exempted from
> > + * ->mapping poisoning and checks.  Also see the macro TAIL_MAPPING.
> > + */
> > +#define  TAIL_MAPPING_REUSED_MAX  (2)
> 
> More importantly, I think this is over-parametrisation.  If you start to
> use extra fields in struct folio, just change the code in page_alloc.c
> directly.

One should at least also need to change __split_huge_page_tail() on the
BUG_ON() with the hard-coded "tail > 2"?

I wanted to link all these pieces together, and the use case is when anyone
would like to e.g. reuse tail page 3 of a folio, hence put the macro here.
diff mbox series

Patch

diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 291c05cacd48..3f2b0d46f5d6 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -248,6 +248,15 @@  static inline struct page *encoded_page_ptr(struct encoded_page *page)
 	return (struct page *)(~ENCODE_PAGE_BITS & (unsigned long)page);
 }
 
+/*
+ * This macro defines the maximum tail pages (of a folio) that can have the
+ * page->mapping field reused (offset 12 for 32bits, or 24 for 64bits).
+ *
+ * When the tail page's mapping field reused, it'll be exempted from
+ * ->mapping poisoning and checks.  Also see the macro TAIL_MAPPING.
+ */
+#define  TAIL_MAPPING_REUSED_MAX  (2)
+
 /**
  * struct folio - Represents a contiguous set of bytes.
  * @flags: Identical to the page flags.
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 0b709d2c46c6..72f244e16dcb 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2444,9 +2444,9 @@  static void __split_huge_page_tail(struct page *head, int tail,
 			 (1L << PG_dirty) |
 			 LRU_GEN_MASK | LRU_REFS_MASK));
 
-	/* ->mapping in first and second tail page is replaced by other uses */
-	VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING,
-			page_tail);
+	/* ->mapping in <=TAIL_MAPPING_REUSED_MAX tail pages are reused */
+	VM_BUG_ON_PAGE(tail > TAIL_MAPPING_REUSED_MAX &&
+		       page_tail->mapping != TAIL_MAPPING, page_tail);
 	page_tail->mapping = head->mapping;
 	page_tail->index = head->index + tail;