]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
mm/lru: Add pageset LRU functions
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 25 Feb 2021 14:47:41 +0000 (09:47 -0500)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Sat, 28 Aug 2021 02:52:21 +0000 (22:52 -0400)
Handle arbitrary-order pagesets being added to the LRU.  By definition,
all pages being added to the LRU were already head or base pages, but
call page_pageset() 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: Mike Rapoport <rppt@linux.ibm.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Documentation/core-api/mm-api.rst
include/linux/mm_inline.h
include/trace/events/pagemap.h

index 5c459ee2accee833d2831524dba0af39c878be62..971149f5d24164c50aa63b43515921a25f4b7b7d 100644 (file)
@@ -95,6 +95,7 @@ More Memory Management Functions
 .. kernel-doc:: mm/mempolicy.c
 .. kernel-doc:: include/linux/mm_types.h
    :internal:
+.. kernel-doc:: include/linux/mm_inline.h
 .. kernel-doc:: include/linux/page-flags.h
 .. kernel-doc:: include/linux/mm.h
    :internal:
index 355ea1ee32bd745d510d9ef2ec403862f188dc70..1a05c847d367b2f438e14c752f813cf0f76e1be8 100644 (file)
@@ -6,27 +6,33 @@
 #include <linux/swap.h>
 
 /**
- * page_is_file_lru - should the page be on a file LRU or anon LRU?
- * @page: the page 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.
+ * pageset_is_file_lru - Should the pageset be on a file LRU or anon LRU?
+ * @pageset: The pageset to test.
  *
  * 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 pageset 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 pageset onto the
+ * right LRU list and to account pagesets correctly.
+ * 1 if @pageset is a regular filesystem backed page cache pageset
+ * or a lazily freed anonymous pageset (e.g. via MADV_FREE).
+ * 0 if @pageset is a normal anonymous pageset, a tmpfs pageset or otherwise
+ * ram or swap backed pageset.
  */
+static inline int pageset_is_file_lru(struct pageset *pageset)
+{
+       return !pageset_test_swapbacked(pageset);
+}
+
 static inline int page_is_file_lru(struct page *page)
 {
-       return !PageSwapBacked(page);
+       return pageset_is_file_lru(page_pageset(page));
 }
 
 static __always_inline void update_lru_size(struct lruvec *lruvec,
                                enum lru_list lru, enum zone_type zid,
-                               int nr_pages)
+                               long nr_pages)
 {
        struct pglist_data *pgdat = lruvec_pgdat(lruvec);
 
@@ -39,69 +45,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
+ * __pageset_clear_lru_flags - Clear page lru flags before releasing a page.
+ * @pageset: The pageset 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 __pageset_clear_lru_flags(struct pageset *pageset)
 {
-       VM_BUG_ON_PAGE(!PageLRU(page), page);
+       VM_BUG_ON_PAGESET(!pageset_test_lru(pageset), pageset);
 
-       __ClearPageLRU(page);
+       __pageset_clear_lru(pageset);
 
        /* this shouldn't happen, so leave the flags to bad_page() */
-       if (PageActive(page) && PageUnevictable(page))
+       if (pageset_test_active(pageset) && pageset_test_unevictable(pageset))
                return;
 
-       __ClearPageActive(page);
-       __ClearPageUnevictable(page);
+       __pageset_clear_active(pageset);
+       __pageset_clear_unevictable(pageset);
+}
+
+static __always_inline void __clear_page_lru_flags(struct page *page)
+{
+       __pageset_clear_lru_flags(page_pageset(page));
 }
 
 /**
- * page_lru - which LRU list should a page be on?
- * @page: the page to test
+ * pageset_lru_list - Which LRU list should a pageset be on?
+ * @pageset: The pageset to test.
  *
- * Returns the LRU list a page should be on, as an index
+ * Return: The LRU list a pageset 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 pageset_lru_list(struct pageset *pageset)
 {
        enum lru_list lru;
 
-       VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page);
+       VM_BUG_ON_PAGESET(pageset_test_active(pageset) && pageset_test_unevictable(pageset), pageset);
 
-       if (PageUnevictable(page))
+       if (pageset_test_unevictable(pageset))
                return LRU_UNEVICTABLE;
 
-       lru = page_is_file_lru(page) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON;
-       if (PageActive(page))
+       lru = pageset_is_file_lru(pageset) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON;
+       if (pageset_test_active(pageset))
                lru += LRU_ACTIVE;
 
        return lru;
 }
 
+static __always_inline
+void lruvec_add_pageset(struct lruvec *lruvec, struct pageset *pageset)
+{
+       enum lru_list lru = pageset_lru_list(pageset);
+
+       update_lru_size(lruvec, lru, pageset_zonenum(pageset),
+                       pageset_nr_pages(pageset));
+       list_add(&pageset->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_pageset(lruvec, page_pageset(page));
+}
 
-       update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
-       list_add(&page->lru, &lruvec->lists[lru]);
+static __always_inline
+void lruvec_add_pageset_tail(struct lruvec *lruvec, struct pageset *pageset)
+{
+       enum lru_list lru = pageset_lru_list(pageset);
+
+       update_lru_size(lruvec, lru, pageset_zonenum(pageset),
+                       pageset_nr_pages(pageset));
+       list_add_tail(&pageset->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_pageset_tail(lruvec, page_pageset(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_pageset(struct lruvec *lruvec, struct pageset *pageset)
+{
+       list_del(&pageset->lru);
+       update_lru_size(lruvec, pageset_lru_list(pageset), pageset_zonenum(pageset),
+                       -pageset_nr_pages(pageset));
 }
 
 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_pageset(lruvec, page_pageset(page));
 }
 #endif
index 1d28431e85bdca40b1c8eab304f992dc3305821c..5955dc5b18ec8de7f1d86a276d55e4d8661376d9 100644 (file)
@@ -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    = pageset_lru_list(page_pageset(page));
                __entry->flags  = trace_pagemap_flags(page);
        ),