diff mbox series

[v14,011/138] mm/lru: Add folio LRU functions

Message ID 20210715033704.692967-12-willy@infradead.org (mailing list archive)
State New
Headers show
Series Memory folios | expand

Commit Message

Matthew Wilcox July 15, 2021, 3:34 a.m. UTC
Handle arbitrary-order folios being added to the LRU.  By definition,
all pages being added to the LRU were already head or base pages, but
call page_folio() on them anyway to get the type right and avoid the
buried calls to compound_head().

Saves 783 bytes of kernel text; no functions grow.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Yu Zhao <yuzhao@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: David Howells <dhowells@redhat.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
---
 include/linux/mm_inline.h      | 98 ++++++++++++++++++++++------------
 include/trace/events/pagemap.h |  2 +-
 2 files changed, 65 insertions(+), 35 deletions(-)

Comments

Mike Rapoport July 20, 2021, 10:44 a.m. UTC | #1
On Thu, Jul 15, 2021 at 04:34:57AM +0100, Matthew Wilcox (Oracle) wrote:
> Handle arbitrary-order folios being added to the LRU.  By definition,
> all pages being added to the LRU were already head or base pages, but
> call page_folio() on them anyway to get the type right and avoid the
> buried calls to compound_head().
> 
> Saves 783 bytes of kernel text; no functions grow.
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Reviewed-by: Yu Zhao <yuzhao@google.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: David Howells <dhowells@redhat.com>
> Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> ---
>  include/linux/mm_inline.h      | 98 ++++++++++++++++++++++------------
>  include/trace/events/pagemap.h |  2 +-
>  2 files changed, 65 insertions(+), 35 deletions(-)

Acked-by: Mike Rapoport <rppt@linux.ibm.com>

> diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
> index 355ea1ee32bd..ee155d19885e 100644
> --- a/include/linux/mm_inline.h
> +++ b/include/linux/mm_inline.h
> @@ -6,22 +6,27 @@
>  #include <linux/swap.h>
>  
>  /**
> - * page_is_file_lru - should the page be on a file LRU or anon LRU?
> - * @page: the page to test
> + * folio_is_file_lru - should the folio be on a file LRU or anon LRU?
> + * @folio: the folio to test
>   *
> - * Returns 1 if @page is a regular filesystem backed page cache page or a lazily
> - * freed anonymous page (e.g. via MADV_FREE).  Returns 0 if @page is a normal
> - * anonymous page, a tmpfs page or otherwise ram or swap backed page.  Used by
> - * functions that manipulate the LRU lists, to sort a page onto the right LRU
> - * list.
> + * Returns 1 if @folio is a regular filesystem backed page cache folio
> + * or a lazily freed anonymous folio (e.g. via MADV_FREE).  Returns 0 if
> + * @folio is a normal anonymous folio, a tmpfs folio or otherwise ram or
> + * swap backed folio.  Used by functions that manipulate the LRU lists,
> + * to sort a folio onto the right LRU list.
>   *
>   * We would like to get this info without a page flag, but the state
> - * needs to survive until the page is last deleted from the LRU, which
> + * needs to survive until the folio is last deleted from the LRU, which
>   * could be as far down as __page_cache_release.

It seems mm_inline.h is not a part of generated API docs, otherwise
kerneldoc would be unhappy about missing Return: description.

>   */
> +static inline int folio_is_file_lru(struct folio *folio)
> +{
> +	return !folio_test_swapbacked(folio);
> +}
> +
>  static inline int page_is_file_lru(struct page *page)
>  {
> -	return !PageSwapBacked(page);
> +	return folio_is_file_lru(page_folio(page));
>  }
>  
>  static __always_inline void update_lru_size(struct lruvec *lruvec,
> @@ -39,69 +44,94 @@ static __always_inline void update_lru_size(struct lruvec *lruvec,
>  }
>  
>  /**
> - * __clear_page_lru_flags - clear page lru flags before releasing a page
> - * @page: the page that was on lru and now has a zero reference
> + * __folio_clear_lru_flags - clear page lru flags before releasing a page
> + * @folio: The folio that was on lru and now has a zero reference
>   */
> -static __always_inline void __clear_page_lru_flags(struct page *page)
> +static __always_inline void __folio_clear_lru_flags(struct folio *folio)
>  {
> -	VM_BUG_ON_PAGE(!PageLRU(page), page);
> +	VM_BUG_ON_FOLIO(!folio_test_lru(folio), folio);
>  
> -	__ClearPageLRU(page);
> +	__folio_clear_lru(folio);
>  
>  	/* this shouldn't happen, so leave the flags to bad_page() */
> -	if (PageActive(page) && PageUnevictable(page))
> +	if (folio_test_active(folio) && folio_test_unevictable(folio))
>  		return;
>  
> -	__ClearPageActive(page);
> -	__ClearPageUnevictable(page);
> +	__folio_clear_active(folio);
> +	__folio_clear_unevictable(folio);
> +}
> +
> +static __always_inline void __clear_page_lru_flags(struct page *page)
> +{
> +	__folio_clear_lru_flags(page_folio(page));
>  }
>  
>  /**
> - * page_lru - which LRU list should a page be on?
> - * @page: the page to test
> + * folio_lru_list - which LRU list should a folio be on?
> + * @folio: the folio to test
>   *
> - * Returns the LRU list a page should be on, as an index
> + * Returns the LRU list a folio should be on, as an index

      ^ Return: 

>   * into the array of LRU lists.
>   */
> -static __always_inline enum lru_list page_lru(struct page *page)
> +static __always_inline enum lru_list folio_lru_list(struct folio *folio)
>  {
>  	enum lru_list lru;
>  
> -	VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page);
> +	VM_BUG_ON_FOLIO(folio_test_active(folio) && folio_test_unevictable(folio), folio);
>  
> -	if (PageUnevictable(page))
> +	if (folio_test_unevictable(folio))
>  		return LRU_UNEVICTABLE;
>  
> -	lru = page_is_file_lru(page) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON;
> -	if (PageActive(page))
> +	lru = folio_is_file_lru(folio) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON;
> +	if (folio_test_active(folio))
>  		lru += LRU_ACTIVE;
>  
>  	return lru;
>  }

. . .
Matthew Wilcox July 20, 2021, 1:10 p.m. UTC | #2
On Tue, Jul 20, 2021 at 01:44:10PM +0300, Mike Rapoport wrote:
> >  /**
> > - * page_is_file_lru - should the page be on a file LRU or anon LRU?
> > - * @page: the page to test
> > + * folio_is_file_lru - should the folio be on a file LRU or anon LRU?
> > + * @folio: the folio to test
> >   *
> > - * Returns 1 if @page is a regular filesystem backed page cache page or a lazily
> > - * freed anonymous page (e.g. via MADV_FREE).  Returns 0 if @page is a normal
> > - * anonymous page, a tmpfs page or otherwise ram or swap backed page.  Used by
> > - * functions that manipulate the LRU lists, to sort a page onto the right LRU
> > - * list.
> > + * Returns 1 if @folio is a regular filesystem backed page cache folio
> > + * or a lazily freed anonymous folio (e.g. via MADV_FREE).  Returns 0 if
> > + * @folio is a normal anonymous folio, a tmpfs folio or otherwise ram or
> > + * swap backed folio.  Used by functions that manipulate the LRU lists,
> > + * to sort a folio onto the right LRU list.
> >   *
> >   * We would like to get this info without a page flag, but the state
> > - * needs to survive until the page is last deleted from the LRU, which
> > + * needs to survive until the folio is last deleted from the LRU, which
> >   * could be as far down as __page_cache_release.
> 
> It seems mm_inline.h is not a part of generated API docs, otherwise
> kerneldoc would be unhappy about missing Return: description.

kernel-doc doesn't warn about that by default.

    # This check emits a lot of warnings at the moment, because many
    # functions don't have a 'Return' doc section. So until the number
    # of warnings goes sufficiently down, the check is only performed in
    # verbose mode.
    # TODO: always perform the check.
    if ($verbose && !$noret) {
            check_return_section($file, $declaration_name, $return_type);
    }
Matthew Wilcox July 21, 2021, 4:08 a.m. UTC | #3
On Tue, Jul 20, 2021 at 01:44:10PM +0300, Mike Rapoport wrote:
> It seems mm_inline.h is not a part of generated API docs, otherwise
> kerneldoc would be unhappy about missing Return: description.

It isn't, but I did add mm_inline.h to Documentation as part of this
patch (thanks!) and made this change:

 /**
- * folio_is_file_lru - should the folio be on a file LRU or anon LRU?
- * @folio: the folio to test
- *
- * Returns 1 if @folio is a regular filesystem backed page cache folio
- * or a lazily freed anonymous folio (e.g. via MADV_FREE).  Returns 0 if
- * @folio is a normal anonymous folio, a tmpfs folio or otherwise ram or
- * swap backed folio.  Used by functions that manipulate the LRU lists,
- * to sort a folio onto the right LRU list.
+ * folio_is_file_lru - Should the folio be on a file LRU or anon LRU?
+ * @folio: The folio to test.
  *
  * We would like to get this info without a page flag, but the state
  * needs to survive until the folio is last deleted from the LRU, which
  * could be as far down as __page_cache_release.
+ *
+ * Return: An integer (not a boolean!) used to sort a folio onto the
+ * right LRU list and to account folios correctly.
+ * 1 if @folio is a regular filesystem backed page cache folio
+ * or a lazily freed anonymous folio (e.g. via MADV_FREE).
+ * 0 if @folio is a normal anonymous folio, a tmpfs folio or otherwise
+ * ram or swap backed folio.
  */

I wanted to turn those last two sentences into a list, but my
kernel-doc-fu abandoned me.  Feel free to submit a follow-on patch to
fix that ;-)
Mike Rapoport July 21, 2021, 8:39 a.m. UTC | #4
On Wed, Jul 21, 2021 at 05:08:44AM +0100, Matthew Wilcox wrote:
> On Tue, Jul 20, 2021 at 01:44:10PM +0300, Mike Rapoport wrote:
> > It seems mm_inline.h is not a part of generated API docs, otherwise
> > kerneldoc would be unhappy about missing Return: description.
> 
> It isn't, but I did add mm_inline.h to Documentation as part of this
> patch (thanks!) and made this change:
> 
>  /**
> - * folio_is_file_lru - should the folio be on a file LRU or anon LRU?
> - * @folio: the folio to test
> - *
> - * Returns 1 if @folio is a regular filesystem backed page cache folio
> - * or a lazily freed anonymous folio (e.g. via MADV_FREE).  Returns 0 if
> - * @folio is a normal anonymous folio, a tmpfs folio or otherwise ram or
> - * swap backed folio.  Used by functions that manipulate the LRU lists,
> - * to sort a folio onto the right LRU list.
> + * folio_is_file_lru - Should the folio be on a file LRU or anon LRU?
> + * @folio: The folio to test.
>   *
>   * We would like to get this info without a page flag, but the state
>   * needs to survive until the folio is last deleted from the LRU, which
>   * could be as far down as __page_cache_release.
> + *
> + * Return: An integer (not a boolean!) used to sort a folio onto the
> + * right LRU list and to account folios correctly.
> + * 1 if @folio is a regular filesystem backed page cache folio
> + * or a lazily freed anonymous folio (e.g. via MADV_FREE).
> + * 0 if @folio is a normal anonymous folio, a tmpfs folio or otherwise
> + * ram or swap backed folio.
>   */
> 
> I wanted to turn those last two sentences into a list, but my
> kernel-doc-fu abandoned me.  Feel free to submit a follow-on patch to
> fix that ;-)

Here it is ;-)

Feel free to fold it into the original commit if you'd like to.

From 636d1715252f7bd1e87219797153b8baa28774af Mon Sep 17 00:00:00 2001
From: Mike Rapoport <rppt@linux.ibm.com>
Date: Wed, 21 Jul 2021 11:35:15 +0300
Subject: [PATCH] mm/docs: folio_is_file_lru: make return description a list

Reformat return value description of folio_is_file_lru() so that will be
presented as a list in the generated output.

Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
---
 include/linux/mm_inline.h | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index d39537c5471b..b263ac0a2c3a 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -15,10 +15,11 @@
  *
  * Return: An integer (not a boolean!) used to sort a folio onto the
  * right LRU list and to account folios correctly.
- * 1 if @folio is a regular filesystem backed page cache folio
- * or a lazily freed anonymous folio (e.g. via MADV_FREE).
- * 0 if @folio is a normal anonymous folio, a tmpfs folio or otherwise
- * ram or swap backed folio.
+ *
+ * - 1 if @folio is a regular filesystem backed page cache folio
+ *   or a lazily freed anonymous folio (e.g. via MADV_FREE).
+ * - 0 if @folio is a normal anonymous folio, a tmpfs folio or otherwise
+ *   ram or swap backed folio.
  */
 static inline int folio_is_file_lru(struct folio *folio)
 {
Matthew Wilcox July 21, 2021, 11:23 a.m. UTC | #5
On Wed, Jul 21, 2021 at 11:39:15AM +0300, Mike Rapoport wrote:
> On Wed, Jul 21, 2021 at 05:08:44AM +0100, Matthew Wilcox wrote:
> > I wanted to turn those last two sentences into a list, but my
> > kernel-doc-fu abandoned me.  Feel free to submit a follow-on patch to
> > fix that ;-)
> 
> Here it is ;-)

Did you try it?  Here's what that turns into with htmldoc:

Description

We would like to get this info without a page flag, but the state needs
to survive until the folio is last deleted from the LRU, which could be
as far down as __page_cache_release.

 * 1 if folio is a regular filesystem backed page cache folio or a
   lazily freed anonymous folio (e.g. via MADV_FREE).
 * 0 if folio is a normal anonymous folio, a tmpfs folio or otherwise
   ram or swap backed folio.

Return

An integer (not a boolean!) used to sort a folio onto the right LRU list
and to account folios correctly.

Yes, we get a bulleted list, but it's placed in the wrong section!

Adding linux-doc for additional insight into this problem.
For their reference, here's the input:

/**
 * folio_is_file_lru - Should the folio be on a file LRU or anon LRU?
 * @folio: The folio to test.
 *
 * We would like to get this info without a page flag, but the state
 * needs to survive until the folio is last deleted from the LRU, which
 * could be as far down as __page_cache_release.
 *
 * Return: An integer (not a boolean!) used to sort a folio onto the
 * right LRU list and to account folios correctly.
 *
 * - 1 if @folio is a regular filesystem backed page cache folio
 *   or a lazily freed anonymous folio (e.g. via MADV_FREE).
 * - 0 if @folio is a normal anonymous folio, a tmpfs folio or otherwise
 *   ram or swap backed folio.
 */
static inline int folio_is_file_lru(struct folio *folio)
Mike Rapoport July 21, 2021, 2:36 p.m. UTC | #6
On Wed, Jul 21, 2021 at 12:23:09PM +0100, Matthew Wilcox wrote:
> On Wed, Jul 21, 2021 at 11:39:15AM +0300, Mike Rapoport wrote:
> > On Wed, Jul 21, 2021 at 05:08:44AM +0100, Matthew Wilcox wrote:
> > > I wanted to turn those last two sentences into a list, but my
> > > kernel-doc-fu abandoned me.  Feel free to submit a follow-on patch to
> > > fix that ;-)
> > 
> > Here it is ;-)
> 
> Did you try it?  Here's what that turns into with htmldoc:

Yes, but I was so happy to see bullets that I missed the fact they are in
the wrong section :(
 
> Description
> 
> We would like to get this info without a page flag, but the state needs
> to survive until the folio is last deleted from the LRU, which could be
> as far down as __page_cache_release.
> 
>  * 1 if folio is a regular filesystem backed page cache folio or a
>    lazily freed anonymous folio (e.g. via MADV_FREE).
>  * 0 if folio is a normal anonymous folio, a tmpfs folio or otherwise
>    ram or swap backed folio.
> 
> Return
> 
> An integer (not a boolean!) used to sort a folio onto the right LRU list
> and to account folios correctly.
> 
> Yes, we get a bulleted list, but it's placed in the wrong section!
> 
> Adding linux-doc for additional insight into this problem.
> For their reference, here's the input:
>
> /**
>  * folio_is_file_lru - Should the folio be on a file LRU or anon LRU?
>  * @folio: The folio to test.
>  *
>  * We would like to get this info without a page flag, but the state
>  * needs to survive until the folio is last deleted from the LRU, which
>  * could be as far down as __page_cache_release.
>  *
>  * Return: An integer (not a boolean!) used to sort a folio onto the
>  * right LRU list and to account folios correctly.
>  *
>  * - 1 if @folio is a regular filesystem backed page cache folio
>  *   or a lazily freed anonymous folio (e.g. via MADV_FREE).
>  * - 0 if @folio is a normal anonymous folio, a tmpfs folio or otherwise
>  *   ram or swap backed folio.
>  */
> static inline int folio_is_file_lru(struct folio *folio)

Hmm, there is some contradiction between kernel-doc assumption that
anything after a blank line is the default (i.e. Description) section and
the sphynx ideas where empty blank lines should be:


	if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) {
		dump_section($file, $section, $contents);
		$section = $section_default;
		$new_start_line = $.;
		$contents = "";
	}

(from scripts/kernel-doc::process_body())
Vlastimil Babka Aug. 10, 2021, 4:01 p.m. UTC | #7
On 7/15/21 5:34 AM, Matthew Wilcox (Oracle) wrote:
> Handle arbitrary-order folios being added to the LRU.  By definition,
> all pages being added to the LRU were already head or base pages, but
> call page_folio() on them anyway to get the type right and avoid the
> buried calls to compound_head().
> 
> Saves 783 bytes of kernel text; no functions grow.
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Reviewed-by: Yu Zhao <yuzhao@google.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: David Howells <dhowells@redhat.com>
> Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>

Acked-by: Vlastimil Babka <vbabka@suse.cz>

Actually looking at the git version, which has also this:

 static __always_inline void update_lru_size(struct lruvec *lruvec,
                                enum lru_list lru, enum zone_type zid,
-                               int nr_pages)
+                               long nr_pages)
 {

Why now and here? Some of the functions called from update_lru_size()
still take int so this looks arbitrary?
Matthew Wilcox Aug. 10, 2021, 5:43 p.m. UTC | #8
On Tue, Aug 10, 2021 at 06:01:16PM +0200, Vlastimil Babka wrote:
> Actually looking at the git version, which has also this:
> 
>  static __always_inline void update_lru_size(struct lruvec *lruvec,
>                                 enum lru_list lru, enum zone_type zid,
> -                               int nr_pages)
> +                               long nr_pages)
>  {
> 
> Why now and here? Some of the functions called from update_lru_size()
> still take int so this looks arbitrary?

I'm still a little freaked out about the lack of warning for:

void f(long n);
void g(unsigned int n) { f(-n); }

so I've decided that the count of pages in a folio is always of type
long.  The actual number is positive, and currently it's between 1 and
1024 (inclusive on both bounds), so it's always going to be
representable in an int.  Narrowing it doesn't cause a bug, so we don't
need to change nr_pages anywhere, but it does no harm to make functions
take a long instead of an int (it may even cause slightly better code
generation, based on the sample of functions I've looked at).

Maybe changing update_lru_size() in this patch is wrong.  I can drop it
if you like.
Vlastimil Babka Aug. 11, 2021, 8:58 a.m. UTC | #9
On 8/10/21 7:43 PM, Matthew Wilcox wrote:
> On Tue, Aug 10, 2021 at 06:01:16PM +0200, Vlastimil Babka wrote:
>> Actually looking at the git version, which has also this:
>> 
>>  static __always_inline void update_lru_size(struct lruvec *lruvec,
>>                                 enum lru_list lru, enum zone_type zid,
>> -                               int nr_pages)
>> +                               long nr_pages)
>>  {
>> 
>> Why now and here? Some of the functions called from update_lru_size()
>> still take int so this looks arbitrary?
> 
> I'm still a little freaked out about the lack of warning for:
> 
> void f(long n);
> void g(unsigned int n) { f(-n); }
> 
> so I've decided that the count of pages in a folio is always of type
> long.  The actual number is positive, and currently it's between 1 and
> 1024 (inclusive on both bounds), so it's always going to be
> representable in an int.  Narrowing it doesn't cause a bug, so we don't
> need to change nr_pages anywhere, but it does no harm to make functions
> take a long instead of an int (it may even cause slightly better code
> generation, based on the sample of functions I've looked at).
> 
> Maybe changing update_lru_size() in this patch is wrong.  I can drop it
> if you like.

It's fine, knowing it wasn't some rebasing error.
diff mbox series

Patch

diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index 355ea1ee32bd..ee155d19885e 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -6,22 +6,27 @@ 
 #include <linux/swap.h>
 
 /**
- * page_is_file_lru - should the page be on a file LRU or anon LRU?
- * @page: the page to test
+ * folio_is_file_lru - should the folio be on a file LRU or anon LRU?
+ * @folio: the folio to test
  *
- * Returns 1 if @page is a regular filesystem backed page cache page or a lazily
- * freed anonymous page (e.g. via MADV_FREE).  Returns 0 if @page is a normal
- * anonymous page, a tmpfs page or otherwise ram or swap backed page.  Used by
- * functions that manipulate the LRU lists, to sort a page onto the right LRU
- * list.
+ * Returns 1 if @folio is a regular filesystem backed page cache folio
+ * or a lazily freed anonymous folio (e.g. via MADV_FREE).  Returns 0 if
+ * @folio is a normal anonymous folio, a tmpfs folio or otherwise ram or
+ * swap backed folio.  Used by functions that manipulate the LRU lists,
+ * to sort a folio onto the right LRU list.
  *
  * We would like to get this info without a page flag, but the state
- * needs to survive until the page is last deleted from the LRU, which
+ * needs to survive until the folio is last deleted from the LRU, which
  * could be as far down as __page_cache_release.
  */
+static inline int folio_is_file_lru(struct folio *folio)
+{
+	return !folio_test_swapbacked(folio);
+}
+
 static inline int page_is_file_lru(struct page *page)
 {
-	return !PageSwapBacked(page);
+	return folio_is_file_lru(page_folio(page));
 }
 
 static __always_inline void update_lru_size(struct lruvec *lruvec,
@@ -39,69 +44,94 @@  static __always_inline void update_lru_size(struct lruvec *lruvec,
 }
 
 /**
- * __clear_page_lru_flags - clear page lru flags before releasing a page
- * @page: the page that was on lru and now has a zero reference
+ * __folio_clear_lru_flags - clear page lru flags before releasing a page
+ * @folio: The folio that was on lru and now has a zero reference
  */
-static __always_inline void __clear_page_lru_flags(struct page *page)
+static __always_inline void __folio_clear_lru_flags(struct folio *folio)
 {
-	VM_BUG_ON_PAGE(!PageLRU(page), page);
+	VM_BUG_ON_FOLIO(!folio_test_lru(folio), folio);
 
-	__ClearPageLRU(page);
+	__folio_clear_lru(folio);
 
 	/* this shouldn't happen, so leave the flags to bad_page() */
-	if (PageActive(page) && PageUnevictable(page))
+	if (folio_test_active(folio) && folio_test_unevictable(folio))
 		return;
 
-	__ClearPageActive(page);
-	__ClearPageUnevictable(page);
+	__folio_clear_active(folio);
+	__folio_clear_unevictable(folio);
+}
+
+static __always_inline void __clear_page_lru_flags(struct page *page)
+{
+	__folio_clear_lru_flags(page_folio(page));
 }
 
 /**
- * page_lru - which LRU list should a page be on?
- * @page: the page to test
+ * folio_lru_list - which LRU list should a folio be on?
+ * @folio: the folio to test
  *
- * Returns the LRU list a page should be on, as an index
+ * Returns the LRU list a folio should be on, as an index
  * into the array of LRU lists.
  */
-static __always_inline enum lru_list page_lru(struct page *page)
+static __always_inline enum lru_list folio_lru_list(struct folio *folio)
 {
 	enum lru_list lru;
 
-	VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page);
+	VM_BUG_ON_FOLIO(folio_test_active(folio) && folio_test_unevictable(folio), folio);
 
-	if (PageUnevictable(page))
+	if (folio_test_unevictable(folio))
 		return LRU_UNEVICTABLE;
 
-	lru = page_is_file_lru(page) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON;
-	if (PageActive(page))
+	lru = folio_is_file_lru(folio) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON;
+	if (folio_test_active(folio))
 		lru += LRU_ACTIVE;
 
 	return lru;
 }
 
+static __always_inline
+void lruvec_add_folio(struct lruvec *lruvec, struct folio *folio)
+{
+	enum lru_list lru = folio_lru_list(folio);
+
+	update_lru_size(lruvec, lru, folio_zonenum(folio),
+			folio_nr_pages(folio));
+	list_add(&folio->lru, &lruvec->lists[lru]);
+}
+
 static __always_inline void add_page_to_lru_list(struct page *page,
 				struct lruvec *lruvec)
 {
-	enum lru_list lru = page_lru(page);
+	lruvec_add_folio(lruvec, page_folio(page));
+}
+
+static __always_inline
+void lruvec_add_folio_tail(struct lruvec *lruvec, struct folio *folio)
+{
+	enum lru_list lru = folio_lru_list(folio);
 
-	update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
-	list_add(&page->lru, &lruvec->lists[lru]);
+	update_lru_size(lruvec, lru, folio_zonenum(folio),
+			folio_nr_pages(folio));
+	list_add_tail(&folio->lru, &lruvec->lists[lru]);
 }
 
 static __always_inline void add_page_to_lru_list_tail(struct page *page,
 				struct lruvec *lruvec)
 {
-	enum lru_list lru = page_lru(page);
+	lruvec_add_folio_tail(lruvec, page_folio(page));
+}
 
-	update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
-	list_add_tail(&page->lru, &lruvec->lists[lru]);
+static __always_inline
+void lruvec_del_folio(struct lruvec *lruvec, struct folio *folio)
+{
+	list_del(&folio->lru);
+	update_lru_size(lruvec, folio_lru_list(folio), folio_zonenum(folio),
+			-folio_nr_pages(folio));
 }
 
 static __always_inline void del_page_from_lru_list(struct page *page,
 				struct lruvec *lruvec)
 {
-	list_del(&page->lru);
-	update_lru_size(lruvec, page_lru(page), page_zonenum(page),
-			-thp_nr_pages(page));
+	lruvec_del_folio(lruvec, page_folio(page));
 }
 #endif
diff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h
index 1d28431e85bd..92ad176210ff 100644
--- a/include/trace/events/pagemap.h
+++ b/include/trace/events/pagemap.h
@@ -41,7 +41,7 @@  TRACE_EVENT(mm_lru_insertion,
 	TP_fast_assign(
 		__entry->page	= page;
 		__entry->pfn	= page_to_pfn(page);
-		__entry->lru	= page_lru(page);
+		__entry->lru	= folio_lru_list(page_folio(page));
 		__entry->flags	= trace_pagemap_flags(page);
 	),