@@ -1284,6 +1284,7 @@ static inline struct folio *virt_to_folio(const void *x)
}
void __folio_put(struct folio *folio);
+void __folio_put_small_nopcp(struct folio *folio);
void put_pages_list(struct list_head *pages);
@@ -1483,6 +1484,28 @@ static inline void folio_put(struct folio *folio)
__folio_put(folio);
}
+/**
+ * folio_put_small_nopcp - Decrement the reference count on a folio.
+ * @folio: The folio.
+ *
+ * This is only for a single page folio to release directly to the buddy
+ * allocator bypassing pcp.
+ *
+ * If the folio's reference count reaches zero, the memory will be
+ * released back to the page allocator and may be used by another
+ * allocation immediately. Do not access the memory or the struct folio
+ * after calling folio_put_small_nopcp() unless you can be sure that it
+ * wasn't the last reference.
+ *
+ * Context: May be called in process or interrupt context, but not in NMI
+ * context. May be called while holding a spinlock.
+ */
+static inline void folio_put_small_nopcp(struct folio *folio)
+{
+ if (folio_put_testzero(folio))
+ __folio_put_small_nopcp(folio);
+}
+
/**
* folio_put_refs - Reduce the reference count on a folio.
* @folio: The folio.
@@ -451,6 +451,7 @@ extern int user_min_free_kbytes;
extern void free_unref_page(struct page *page, unsigned int order);
extern void free_unref_page_list(struct list_head *list);
+extern void free_pages_nopcp(struct page *page, unsigned int order);
extern void zone_pcp_reset(struct zone *zone);
extern void zone_pcp_disable(struct zone *zone);
@@ -565,6 +565,16 @@ static inline void free_the_page(struct page *page, unsigned int order)
__free_pages_ok(page, order, FPI_NONE);
}
+void free_pages_nopcp(struct page *page, unsigned int order)
+{
+ /*
+ * This function will be used in case that the pages are too
+ * cold to keep in pcp e.g. migrc mechanism. So it'd better
+ * release the pages to the tail.
+ */
+ __free_pages_ok(page, order, FPI_TO_TAIL);
+}
+
/*
* Higher-order pages are called "compound pages". They are structured thusly:
*
@@ -106,6 +106,13 @@ static void __folio_put_small(struct folio *folio)
free_unref_page(&folio->page, 0);
}
+void __folio_put_small_nopcp(struct folio *folio)
+{
+ __page_cache_release(folio);
+ mem_cgroup_uncharge(folio);
+ free_pages_nopcp(&folio->page, 0);
+}
+
static void __folio_put_large(struct folio *folio)
{
/*
This is a preparation for migrc mechanism that frees folios at a better time. The mechanism will defer the use of folio_put*() for source folios of migration, that are unlikely to be used and a group of folios will be freed at once at a later time. However, this will pollute pcp so as to inexpectedly free_pcppages_bulk() fresher folios and make pcp get unstable. To facilitate this new mechanism, an additional API has been added that allows folios under migrc's control to be freed directly to buddy bypassing pcp. Signed-off-by: Byungchul Park <byungchul@sk.com> --- include/linux/mm.h | 23 +++++++++++++++++++++++ mm/internal.h | 1 + mm/page_alloc.c | 10 ++++++++++ mm/swap.c | 7 +++++++ 4 files changed, 41 insertions(+)