* [PATCH 00/22] Convert the swap code to be more folio-based
@ 2022-06-17 17:49 Matthew Wilcox (Oracle)
2022-06-17 17:49 ` [PATCH 01/22] mm: Add folios_put() Matthew Wilcox (Oracle)
` (21 more replies)
0 siblings, 22 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:49 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
(resend due to email address mistake)
There's still more to do with the swap code, but this reaps a lot of
the folio benefit. More than 4kB of kernel text saved (with the UEK7
kernel config). I don't know how much that's going to translate into
CPU savings, but some of those compound_head() calls are on every page
free, so it should be noticable. It might even be noticable just from
an I-cache consumption perspective.
This is against next-20220617 plus my prior vmscan patch series. It's in
the middle of an xfstests run right now, so it at least boots.
Matthew Wilcox (Oracle) (22):
mm: Add folios_put()
mm/swap: Add folio_batch_move_lru()
mm/swap: Make __pagevec_lru_add static
mm/swap: Convert lru_add to a folio_batch
mm/swap: Convert lru_deactivate_file to a folio_batch
mm/swap: Convert lru_deactivate to a folio_batch
mm/swap: Convert lru_lazyfree to a folio_batch
mm/swap: Convert activate_page to a folio_batch
mm/swap: Rename lru_pvecs to cpu_fbatches
mm/swap: Pull the CPU conditional out of __lru_add_drain_all()
mm/swap: Optimise lru_add_drain_cpu()
mm/swap: Convert try_to_free_swap to use a folio
mm/swap: Convert release_pages to use a folio internally
mm/swap: Convert put_pages_list to use folios
mm/swap: Convert __put_page() to __folio_put()
mm/swap: Convert __put_single_page() to __folio_put_small()
mm/swap: Convert __put_compound_page() to __folio_put_large()
mm/swap: Convert __page_cache_release() to use a folio
mm: Convert destroy_compound_page() to destroy_large_folio()
mm: Convert page_swap_flags to folio_swap_flags
mm/swap: Convert delete_from_swap_cache() to take a folio
mm/swap: Convert __delete_from_swap_cache() to a folio
include/linux/mm.h | 33 ++-
include/linux/pagemap.h | 2 -
include/linux/pagevec.h | 1 -
mm/memory-failure.c | 5 +-
mm/shmem.c | 4 +-
mm/swap.c | 599 +++++++++++++++++++---------------------
mm/swap.h | 14 +-
mm/swap_state.c | 39 +--
mm/swapfile.c | 23 +-
mm/vmscan.c | 8 +-
net/core/page_pool.c | 2 +-
11 files changed, 359 insertions(+), 371 deletions(-)
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 01/22] mm: Add folios_put()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
@ 2022-06-17 17:49 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 02/22] mm/swap: Add folio_batch_move_lru() Matthew Wilcox (Oracle)
` (20 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:49 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
This is just a wrapper around release_pages() for now. Place the
prototype in mm.h along with folio_put() and folio_put_refs().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/linux/mm.h | 19 +++++++++++++++++++
include/linux/pagemap.h | 2 --
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 82b680261cf0..07a1998c3621 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1251,6 +1251,25 @@ static inline void folio_put_refs(struct folio *folio, int refs)
__put_page(&folio->page);
}
+void release_pages(struct page **pages, int nr);
+
+/**
+ * folios_put - Decrement the reference count on an array of folios.
+ * @folios: The folios.
+ * @nr: How many folios there are.
+ *
+ * Like folio_put(), but for an array of folios. This is more efficient
+ * than writing the loop yourself as it will optimise the locks which
+ * need to be taken if the folios are freed.
+ *
+ * Context: May be called in process or interrupt context, but not in NMI
+ * context. May be called while holding a spinlock.
+ */
+static inline void folios_put(struct folio **folios, unsigned int nr)
+{
+ release_pages((struct page **)folios, nr);
+}
+
static inline void put_page(struct page *page)
{
struct folio *folio = page_folio(page);
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 2a67c0ad7348..7c4748a62841 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -345,8 +345,6 @@ static inline void filemap_nr_thps_dec(struct address_space *mapping)
#endif
}
-void release_pages(struct page **pages, int nr);
-
struct address_space *page_mapping(struct page *);
struct address_space *folio_mapping(struct folio *);
struct address_space *swapcache_mapping(struct folio *);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 02/22] mm/swap: Add folio_batch_move_lru()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
2022-06-17 17:49 ` [PATCH 01/22] mm: Add folios_put() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 03/22] mm/swap: Make __pagevec_lru_add static Matthew Wilcox (Oracle)
` (19 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Start converting the LRU from pagevecs to folio_batches.
Combine the functionality of pagevec_add_and_need_flush() with
pagevec_lru_move_fn() in the new folio_batch_add_and_move().
Convert the lru_rotate pagevec to a folio_batch.
Adds 223 bytes total to kernel text, because we're duplicating
infrastructure. This will be more than made up for in future patches.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 78 +++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 56 insertions(+), 22 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 275a4ea1bc66..a983a1b93e73 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -46,10 +46,10 @@
/* How many pages do we try to swap or page in/out together? */
int page_cluster;
-/* Protecting only lru_rotate.pvec which requires disabling interrupts */
+/* Protecting only lru_rotate.fbatch which requires disabling interrupts */
struct lru_rotate {
local_lock_t lock;
- struct pagevec pvec;
+ struct folio_batch fbatch;
};
static DEFINE_PER_CPU(struct lru_rotate, lru_rotate) = {
.lock = INIT_LOCAL_LOCK(lock),
@@ -214,18 +214,6 @@ static void pagevec_lru_move_fn(struct pagevec *pvec,
pagevec_reinit(pvec);
}
-static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec)
-{
- struct folio *folio = page_folio(page);
-
- if (!folio_test_unevictable(folio)) {
- lruvec_del_folio(lruvec, folio);
- folio_clear_active(folio);
- lruvec_add_folio_tail(lruvec, folio);
- __count_vm_events(PGROTATED, folio_nr_pages(folio));
- }
-}
-
/* return true if pagevec needs to drain */
static bool pagevec_add_and_need_flush(struct pagevec *pvec, struct page *page)
{
@@ -238,6 +226,52 @@ static bool pagevec_add_and_need_flush(struct pagevec *pvec, struct page *page)
return ret;
}
+typedef void (*move_fn_t)(struct lruvec *lruvec, struct folio *folio);
+
+static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn)
+{
+ int i;
+ struct lruvec *lruvec = NULL;
+ unsigned long flags = 0;
+
+ for (i = 0; i < folio_batch_count(fbatch); i++) {
+ struct folio *folio = fbatch->folios[i];
+
+ /* block memcg migration while the folio moves between lru */
+ if (!folio_test_clear_lru(folio))
+ continue;
+
+ lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
+ move_fn(lruvec, folio);
+
+ folio_set_lru(folio);
+ }
+
+ if (lruvec)
+ unlock_page_lruvec_irqrestore(lruvec, flags);
+ folios_put(fbatch->folios, folio_batch_count(fbatch));
+ folio_batch_init(fbatch);
+}
+
+static void folio_batch_add_and_move(struct folio_batch *fbatch,
+ struct folio *folio, move_fn_t move_fn)
+{
+ if (folio_batch_add(fbatch, folio) && !folio_test_large(folio) &&
+ !lru_cache_disabled())
+ return;
+ folio_batch_move_lru(fbatch, move_fn);
+}
+
+static void lru_move_tail_fn(struct lruvec *lruvec, struct folio *folio)
+{
+ if (!folio_test_unevictable(folio)) {
+ lruvec_del_folio(lruvec, folio);
+ folio_clear_active(folio);
+ lruvec_add_folio_tail(lruvec, folio);
+ __count_vm_events(PGROTATED, folio_nr_pages(folio));
+ }
+}
+
/*
* Writeback is about to end against a folio which has been marked for
* immediate reclaim. If it still appears to be reclaimable, move it
@@ -249,14 +283,13 @@ void folio_rotate_reclaimable(struct folio *folio)
{
if (!folio_test_locked(folio) && !folio_test_dirty(folio) &&
!folio_test_unevictable(folio) && folio_test_lru(folio)) {
- struct pagevec *pvec;
+ struct folio_batch *fbatch;
unsigned long flags;
folio_get(folio);
local_lock_irqsave(&lru_rotate.lock, flags);
- pvec = this_cpu_ptr(&lru_rotate.pvec);
- if (pagevec_add_and_need_flush(pvec, &folio->page))
- pagevec_lru_move_fn(pvec, pagevec_move_tail_fn);
+ fbatch = this_cpu_ptr(&lru_rotate.fbatch);
+ folio_batch_add_and_move(fbatch, folio, lru_move_tail_fn);
local_unlock_irqrestore(&lru_rotate.lock, flags);
}
}
@@ -595,19 +628,20 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec)
*/
void lru_add_drain_cpu(int cpu)
{
+ struct folio_batch *fbatch;
struct pagevec *pvec = &per_cpu(lru_pvecs.lru_add, cpu);
if (pagevec_count(pvec))
__pagevec_lru_add(pvec);
- pvec = &per_cpu(lru_rotate.pvec, cpu);
+ fbatch = &per_cpu(lru_rotate.fbatch, cpu);
/* Disabling interrupts below acts as a compiler barrier. */
- if (data_race(pagevec_count(pvec))) {
+ if (data_race(folio_batch_count(fbatch))) {
unsigned long flags;
/* No harm done if a racing interrupt already did this */
local_lock_irqsave(&lru_rotate.lock, flags);
- pagevec_lru_move_fn(pvec, pagevec_move_tail_fn);
+ folio_batch_move_lru(fbatch, lru_move_tail_fn);
local_unlock_irqrestore(&lru_rotate.lock, flags);
}
@@ -824,7 +858,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
if (pagevec_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
- data_race(pagevec_count(&per_cpu(lru_rotate.pvec, cpu))) ||
+ data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
pagevec_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
pagevec_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
pagevec_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 03/22] mm/swap: Make __pagevec_lru_add static
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
2022-06-17 17:49 ` [PATCH 01/22] mm: Add folios_put() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 02/22] mm/swap: Add folio_batch_move_lru() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 04/22] mm/swap: Convert lru_add to a folio_batch Matthew Wilcox (Oracle)
` (18 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
__pagevec_lru_add has no callers outside swap.c, so make it static,
and move it to a more logical position in the file.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/linux/pagevec.h | 1 -
mm/swap.c | 126 ++++++++++++++++++++--------------------
2 files changed, 63 insertions(+), 64 deletions(-)
diff --git a/include/linux/pagevec.h b/include/linux/pagevec.h
index 6649154a2115..215eb6c3bdc9 100644
--- a/include/linux/pagevec.h
+++ b/include/linux/pagevec.h
@@ -26,7 +26,6 @@ struct pagevec {
};
void __pagevec_release(struct pagevec *pvec);
-void __pagevec_lru_add(struct pagevec *pvec);
unsigned pagevec_lookup_range_tag(struct pagevec *pvec,
struct address_space *mapping, pgoff_t *index, pgoff_t end,
xa_mark_t tag);
diff --git a/mm/swap.c b/mm/swap.c
index a983a1b93e73..6b015096ef4a 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -228,6 +228,69 @@ static bool pagevec_add_and_need_flush(struct pagevec *pvec, struct page *page)
typedef void (*move_fn_t)(struct lruvec *lruvec, struct folio *folio);
+static void __pagevec_lru_add_fn(struct folio *folio, struct lruvec *lruvec)
+{
+ int was_unevictable = folio_test_clear_unevictable(folio);
+ long nr_pages = folio_nr_pages(folio);
+
+ VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
+
+ folio_set_lru(folio);
+ /*
+ * Is an smp_mb__after_atomic() still required here, before
+ * folio_evictable() tests PageMlocked, to rule out the possibility
+ * of stranding an evictable folio on an unevictable LRU? I think
+ * not, because __munlock_page() only clears PageMlocked while the LRU
+ * lock is held.
+ *
+ * (That is not true of __page_cache_release(), and not necessarily
+ * true of release_pages(): but those only clear PageMlocked after
+ * put_page_testzero() has excluded any other users of the page.)
+ */
+ if (folio_evictable(folio)) {
+ if (was_unevictable)
+ __count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages);
+ } else {
+ folio_clear_active(folio);
+ folio_set_unevictable(folio);
+ /*
+ * folio->mlock_count = !!folio_test_mlocked(folio)?
+ * But that leaves __mlock_page() in doubt whether another
+ * actor has already counted the mlock or not. Err on the
+ * safe side, underestimate, let page reclaim fix it, rather
+ * than leaving a page on the unevictable LRU indefinitely.
+ */
+ folio->mlock_count = 0;
+ if (!was_unevictable)
+ __count_vm_events(UNEVICTABLE_PGCULLED, nr_pages);
+ }
+
+ lruvec_add_folio(lruvec, folio);
+ trace_mm_lru_insertion(folio);
+}
+
+/*
+ * Add the passed pages to the LRU, then drop the caller's refcount
+ * on them. Reinitialises the caller's pagevec.
+ */
+static void __pagevec_lru_add(struct pagevec *pvec)
+{
+ int i;
+ struct lruvec *lruvec = NULL;
+ unsigned long flags = 0;
+
+ for (i = 0; i < pagevec_count(pvec); i++) {
+ struct folio *folio = page_folio(pvec->pages[i]);
+
+ lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
+ __pagevec_lru_add_fn(folio, lruvec);
+ }
+ if (lruvec)
+ unlock_page_lruvec_irqrestore(lruvec, flags);
+ release_pages(pvec->pages, pvec->nr);
+ pagevec_reinit(pvec);
+}
+
static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn)
{
int i;
@@ -1036,69 +1099,6 @@ void __pagevec_release(struct pagevec *pvec)
}
EXPORT_SYMBOL(__pagevec_release);
-static void __pagevec_lru_add_fn(struct folio *folio, struct lruvec *lruvec)
-{
- int was_unevictable = folio_test_clear_unevictable(folio);
- long nr_pages = folio_nr_pages(folio);
-
- VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
-
- folio_set_lru(folio);
- /*
- * Is an smp_mb__after_atomic() still required here, before
- * folio_evictable() tests PageMlocked, to rule out the possibility
- * of stranding an evictable folio on an unevictable LRU? I think
- * not, because __munlock_page() only clears PageMlocked while the LRU
- * lock is held.
- *
- * (That is not true of __page_cache_release(), and not necessarily
- * true of release_pages(): but those only clear PageMlocked after
- * put_page_testzero() has excluded any other users of the page.)
- */
- if (folio_evictable(folio)) {
- if (was_unevictable)
- __count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages);
- } else {
- folio_clear_active(folio);
- folio_set_unevictable(folio);
- /*
- * folio->mlock_count = !!folio_test_mlocked(folio)?
- * But that leaves __mlock_page() in doubt whether another
- * actor has already counted the mlock or not. Err on the
- * safe side, underestimate, let page reclaim fix it, rather
- * than leaving a page on the unevictable LRU indefinitely.
- */
- folio->mlock_count = 0;
- if (!was_unevictable)
- __count_vm_events(UNEVICTABLE_PGCULLED, nr_pages);
- }
-
- lruvec_add_folio(lruvec, folio);
- trace_mm_lru_insertion(folio);
-}
-
-/*
- * Add the passed pages to the LRU, then drop the caller's refcount
- * on them. Reinitialises the caller's pagevec.
- */
-void __pagevec_lru_add(struct pagevec *pvec)
-{
- int i;
- struct lruvec *lruvec = NULL;
- unsigned long flags = 0;
-
- for (i = 0; i < pagevec_count(pvec); i++) {
- struct folio *folio = page_folio(pvec->pages[i]);
-
- lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
- __pagevec_lru_add_fn(folio, lruvec);
- }
- if (lruvec)
- unlock_page_lruvec_irqrestore(lruvec, flags);
- release_pages(pvec->pages, pvec->nr);
- pagevec_reinit(pvec);
-}
-
/**
* folio_batch_remove_exceptionals() - Prune non-folios from a batch.
* @fbatch: The batch to prune
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 04/22] mm/swap: Convert lru_add to a folio_batch
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (2 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 03/22] mm/swap: Make __pagevec_lru_add static Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 05/22] mm/swap: Convert lru_deactivate_file " Matthew Wilcox (Oracle)
` (17 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
When adding folios to the LRU for the first time, the LRU flag will
already be clear, so skip the test-and-clear part of moving from one
LRU to another.
Removes 285 bytes from kernel text, mostly due to removing
__pagevec_lru_add().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 75 +++++++++++++++++++------------------------------------
1 file changed, 26 insertions(+), 49 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 6b015096ef4a..e9d54cb49cd3 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -61,7 +61,7 @@ static DEFINE_PER_CPU(struct lru_rotate, lru_rotate) = {
*/
struct lru_pvecs {
local_lock_t lock;
- struct pagevec lru_add;
+ struct folio_batch lru_add;
struct pagevec lru_deactivate_file;
struct pagevec lru_deactivate;
struct pagevec lru_lazyfree;
@@ -228,14 +228,13 @@ static bool pagevec_add_and_need_flush(struct pagevec *pvec, struct page *page)
typedef void (*move_fn_t)(struct lruvec *lruvec, struct folio *folio);
-static void __pagevec_lru_add_fn(struct folio *folio, struct lruvec *lruvec)
+static void lru_add_fn(struct lruvec *lruvec, struct folio *folio)
{
int was_unevictable = folio_test_clear_unevictable(folio);
long nr_pages = folio_nr_pages(folio);
VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
- folio_set_lru(folio);
/*
* Is an smp_mb__after_atomic() still required here, before
* folio_evictable() tests PageMlocked, to rule out the possibility
@@ -269,28 +268,6 @@ static void __pagevec_lru_add_fn(struct folio *folio, struct lruvec *lruvec)
trace_mm_lru_insertion(folio);
}
-/*
- * Add the passed pages to the LRU, then drop the caller's refcount
- * on them. Reinitialises the caller's pagevec.
- */
-static void __pagevec_lru_add(struct pagevec *pvec)
-{
- int i;
- struct lruvec *lruvec = NULL;
- unsigned long flags = 0;
-
- for (i = 0; i < pagevec_count(pvec); i++) {
- struct folio *folio = page_folio(pvec->pages[i]);
-
- lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
- __pagevec_lru_add_fn(folio, lruvec);
- }
- if (lruvec)
- unlock_page_lruvec_irqrestore(lruvec, flags);
- release_pages(pvec->pages, pvec->nr);
- pagevec_reinit(pvec);
-}
-
static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn)
{
int i;
@@ -301,7 +278,7 @@ static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn)
struct folio *folio = fbatch->folios[i];
/* block memcg migration while the folio moves between lru */
- if (!folio_test_clear_lru(folio))
+ if (move_fn != lru_add_fn && !folio_test_clear_lru(folio))
continue;
lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
@@ -473,26 +450,26 @@ static void folio_activate(struct folio *folio)
static void __lru_cache_activate_folio(struct folio *folio)
{
- struct pagevec *pvec;
+ struct folio_batch *fbatch;
int i;
local_lock(&lru_pvecs.lock);
- pvec = this_cpu_ptr(&lru_pvecs.lru_add);
+ fbatch = this_cpu_ptr(&lru_pvecs.lru_add);
/*
- * Search backwards on the optimistic assumption that the page being
- * activated has just been added to this pagevec. Note that only
- * the local pagevec is examined as a !PageLRU page could be in the
+ * Search backwards on the optimistic assumption that the folio being
+ * activated has just been added to this batch. Note that only
+ * the local batch is examined as a !LRU folio could be in the
* process of being released, reclaimed, migrated or on a remote
- * pagevec that is currently being drained. Furthermore, marking
- * a remote pagevec's page PageActive potentially hits a race where
- * a page is marked PageActive just after it is added to the inactive
+ * batch that is currently being drained. Furthermore, marking
+ * a remote batch's folio active potentially hits a race where
+ * a folio is marked active just after it is added to the inactive
* list causing accounting errors and BUG_ON checks to trigger.
*/
- for (i = pagevec_count(pvec) - 1; i >= 0; i--) {
- struct page *pagevec_page = pvec->pages[i];
+ for (i = folio_batch_count(fbatch) - 1; i >= 0; i--) {
+ struct folio *batch_folio = fbatch->folios[i];
- if (pagevec_page == &folio->page) {
+ if (batch_folio == folio) {
folio_set_active(folio);
break;
}
@@ -551,16 +528,16 @@ EXPORT_SYMBOL(folio_mark_accessed);
*/
void folio_add_lru(struct folio *folio)
{
- struct pagevec *pvec;
+ struct folio_batch *fbatch;
- VM_BUG_ON_FOLIO(folio_test_active(folio) && folio_test_unevictable(folio), folio);
+ VM_BUG_ON_FOLIO(folio_test_active(folio) &&
+ folio_test_unevictable(folio), folio);
VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
folio_get(folio);
local_lock(&lru_pvecs.lock);
- pvec = this_cpu_ptr(&lru_pvecs.lru_add);
- if (pagevec_add_and_need_flush(pvec, &folio->page))
- __pagevec_lru_add(pvec);
+ fbatch = this_cpu_ptr(&lru_pvecs.lru_add);
+ folio_batch_add_and_move(fbatch, folio, lru_add_fn);
local_unlock(&lru_pvecs.lock);
}
EXPORT_SYMBOL(folio_add_lru);
@@ -691,11 +668,11 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec)
*/
void lru_add_drain_cpu(int cpu)
{
- struct folio_batch *fbatch;
- struct pagevec *pvec = &per_cpu(lru_pvecs.lru_add, cpu);
+ struct folio_batch *fbatch = &per_cpu(lru_pvecs.lru_add, cpu);
+ struct pagevec *pvec;
- if (pagevec_count(pvec))
- __pagevec_lru_add(pvec);
+ if (folio_batch_count(fbatch))
+ folio_batch_move_lru(fbatch, lru_add_fn);
fbatch = &per_cpu(lru_rotate.fbatch, cpu);
/* Disabling interrupts below acts as a compiler barrier. */
@@ -920,7 +897,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
for_each_online_cpu(cpu) {
struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
- if (pagevec_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
+ if (folio_batch_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
pagevec_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
pagevec_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
@@ -1084,8 +1061,8 @@ EXPORT_SYMBOL(release_pages);
* OK from a correctness point of view but is inefficient - those pages may be
* cache-warm and we want to give them back to the page allocator ASAP.
*
- * So __pagevec_release() will drain those queues here. __pagevec_lru_add()
- * and __pagevec_lru_add_active() call release_pages() directly to avoid
+ * So __pagevec_release() will drain those queues here.
+ * folio_batch_move_lru() calls folios_put() directly to avoid
* mutual recursion.
*/
void __pagevec_release(struct pagevec *pvec)
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 05/22] mm/swap: Convert lru_deactivate_file to a folio_batch
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (3 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 04/22] mm/swap: Convert lru_add to a folio_batch Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 06/22] mm/swap: Convert lru_deactivate " Matthew Wilcox (Oracle)
` (16 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Use a folio throughout lru_deactivate_file_fn(), removing many hidden
calls to compound_head(). Shrinks the kernel by 864 bytes of text.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 82 ++++++++++++++++++++++++++-----------------------------
1 file changed, 39 insertions(+), 43 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index e9d54cb49cd3..1ca432163fe4 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -62,7 +62,7 @@ static DEFINE_PER_CPU(struct lru_rotate, lru_rotate) = {
struct lru_pvecs {
local_lock_t lock;
struct folio_batch lru_add;
- struct pagevec lru_deactivate_file;
+ struct folio_batch lru_deactivate_file;
struct pagevec lru_deactivate;
struct pagevec lru_lazyfree;
#ifdef CONFIG_SMP
@@ -562,56 +562,57 @@ void lru_cache_add_inactive_or_unevictable(struct page *page,
}
/*
- * If the page can not be invalidated, it is moved to the
+ * If the folio cannot be invalidated, it is moved to the
* inactive list to speed up its reclaim. It is moved to the
* head of the list, rather than the tail, to give the flusher
* threads some time to write it out, as this is much more
* effective than the single-page writeout from reclaim.
*
- * If the page isn't page_mapped and dirty/writeback, the page
- * could reclaim asap using PG_reclaim.
+ * If the folio isn't mapped and dirty/writeback, the folio
+ * could be reclaimed asap using the reclaim flag.
*
- * 1. active, mapped page -> none
- * 2. active, dirty/writeback page -> inactive, head, PG_reclaim
- * 3. inactive, mapped page -> none
- * 4. inactive, dirty/writeback page -> inactive, head, PG_reclaim
+ * 1. active, mapped folio -> none
+ * 2. active, dirty/writeback folio -> inactive, head, reclaim
+ * 3. inactive, mapped folio -> none
+ * 4. inactive, dirty/writeback folio -> inactive, head, reclaim
* 5. inactive, clean -> inactive, tail
* 6. Others -> none
*
- * In 4, why it moves inactive's head, the VM expects the page would
- * be write it out by flusher threads as this is much more effective
+ * In 4, it moves to the head of the inactive list so the folio is
+ * written out by flusher threads as this is much more efficient
* than the single-page writeout from reclaim.
*/
-static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec)
+static void lru_deactivate_file_fn(struct lruvec *lruvec, struct folio *folio)
{
- bool active = PageActive(page);
- int nr_pages = thp_nr_pages(page);
+ bool active = folio_test_active(folio);
+ long nr_pages = folio_nr_pages(folio);
- if (PageUnevictable(page))
+ if (folio_test_unevictable(folio))
return;
- /* Some processes are using the page */
- if (page_mapped(page))
+ /* Some processes are using the folio */
+ if (folio_mapped(folio))
return;
- del_page_from_lru_list(page, lruvec);
- ClearPageActive(page);
- ClearPageReferenced(page);
+ lruvec_del_folio(lruvec, folio);
+ folio_clear_active(folio);
+ folio_clear_referenced(folio);
- if (PageWriteback(page) || PageDirty(page)) {
+ if (folio_test_writeback(folio) || folio_test_dirty(folio)) {
/*
- * PG_reclaim could be raced with end_page_writeback
- * It can make readahead confusing. But race window
- * is _really_ small and it's non-critical problem.
+ * Setting the reclaim flag could race with
+ * folio_end_writeback() and confuse readahead. But the
+ * race window is _really_ small and it's not a critical
+ * problem.
*/
- add_page_to_lru_list(page, lruvec);
- SetPageReclaim(page);
+ lruvec_add_folio(lruvec, folio);
+ folio_set_reclaim(folio);
} else {
/*
- * The page's writeback ends up during pagevec
- * We move that page into tail of inactive.
+ * The folio's writeback ended while it was in the batch.
+ * We move that folio to the tail of the inactive list.
*/
- add_page_to_lru_list_tail(page, lruvec);
+ lruvec_add_folio_tail(lruvec, folio);
__count_vm_events(PGROTATED, nr_pages);
}
@@ -685,9 +686,9 @@ void lru_add_drain_cpu(int cpu)
local_unlock_irqrestore(&lru_rotate.lock, flags);
}
- pvec = &per_cpu(lru_pvecs.lru_deactivate_file, cpu);
- if (pagevec_count(pvec))
- pagevec_lru_move_fn(pvec, lru_deactivate_file_fn);
+ fbatch = &per_cpu(lru_pvecs.lru_deactivate_file, cpu);
+ if (folio_batch_count(fbatch))
+ folio_batch_move_lru(fbatch, lru_deactivate_file_fn);
pvec = &per_cpu(lru_pvecs.lru_deactivate, cpu);
if (pagevec_count(pvec))
@@ -701,32 +702,27 @@ void lru_add_drain_cpu(int cpu)
}
/**
- * deactivate_file_folio() - Forcefully deactivate a file folio.
+ * deactivate_file_folio() - Deactivate a file folio.
* @folio: Folio to deactivate.
*
* This function hints to the VM that @folio is a good reclaim candidate,
* for example if its invalidation fails due to the folio being dirty
* or under writeback.
*
- * Context: Caller holds a reference on the page.
+ * Context: Caller holds a reference on the folio.
*/
void deactivate_file_folio(struct folio *folio)
{
- struct pagevec *pvec;
+ struct folio_batch *fbatch;
- /*
- * In a workload with many unevictable pages such as mprotect,
- * unevictable folio deactivation for accelerating reclaim is pointless.
- */
+ /* Deactivating an unevictable folio will not accelerate reclaim */
if (folio_test_unevictable(folio))
return;
folio_get(folio);
local_lock(&lru_pvecs.lock);
- pvec = this_cpu_ptr(&lru_pvecs.lru_deactivate_file);
-
- if (pagevec_add_and_need_flush(pvec, &folio->page))
- pagevec_lru_move_fn(pvec, lru_deactivate_file_fn);
+ fbatch = this_cpu_ptr(&lru_pvecs.lru_deactivate_file);
+ folio_batch_add_and_move(fbatch, folio, lru_deactivate_file_fn);
local_unlock(&lru_pvecs.lock);
}
@@ -899,7 +895,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
if (folio_batch_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
- pagevec_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
+ folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
pagevec_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
pagevec_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
need_activate_page_drain(cpu) ||
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 06/22] mm/swap: Convert lru_deactivate to a folio_batch
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (4 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 05/22] mm/swap: Convert lru_deactivate_file " Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 07/22] mm/swap: Convert lru_lazyfree " Matthew Wilcox (Oracle)
` (15 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Using folios instead of pages shrinks deactivate_page() and
lru_deactivate_fn() by 778 bytes between them.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 1ca432163fe4..c0323b312a46 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -63,7 +63,7 @@ struct lru_pvecs {
local_lock_t lock;
struct folio_batch lru_add;
struct folio_batch lru_deactivate_file;
- struct pagevec lru_deactivate;
+ struct folio_batch lru_deactivate;
struct pagevec lru_lazyfree;
#ifdef CONFIG_SMP
struct pagevec activate_page;
@@ -623,15 +623,15 @@ static void lru_deactivate_file_fn(struct lruvec *lruvec, struct folio *folio)
}
}
-static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec)
+static void lru_deactivate_fn(struct lruvec *lruvec, struct folio *folio)
{
- if (PageActive(page) && !PageUnevictable(page)) {
- int nr_pages = thp_nr_pages(page);
+ if (folio_test_active(folio) && !folio_test_unevictable(folio)) {
+ long nr_pages = folio_nr_pages(folio);
- del_page_from_lru_list(page, lruvec);
- ClearPageActive(page);
- ClearPageReferenced(page);
- add_page_to_lru_list(page, lruvec);
+ lruvec_del_folio(lruvec, folio);
+ folio_clear_active(folio);
+ folio_clear_referenced(folio);
+ lruvec_add_folio(lruvec, folio);
__count_vm_events(PGDEACTIVATE, nr_pages);
__count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE,
@@ -690,9 +690,9 @@ void lru_add_drain_cpu(int cpu)
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_deactivate_file_fn);
- pvec = &per_cpu(lru_pvecs.lru_deactivate, cpu);
- if (pagevec_count(pvec))
- pagevec_lru_move_fn(pvec, lru_deactivate_fn);
+ fbatch = &per_cpu(lru_pvecs.lru_deactivate, cpu);
+ if (folio_batch_count(fbatch))
+ folio_batch_move_lru(fbatch, lru_deactivate_fn);
pvec = &per_cpu(lru_pvecs.lru_lazyfree, cpu);
if (pagevec_count(pvec))
@@ -736,14 +736,16 @@ void deactivate_file_folio(struct folio *folio)
*/
void deactivate_page(struct page *page)
{
- if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) {
- struct pagevec *pvec;
+ struct folio *folio = page_folio(page);
+ if (folio_test_lru(folio) && folio_test_active(folio) &&
+ !folio_test_unevictable(folio)) {
+ struct folio_batch *fbatch;
+
+ folio_get(folio);
local_lock(&lru_pvecs.lock);
- pvec = this_cpu_ptr(&lru_pvecs.lru_deactivate);
- get_page(page);
- if (pagevec_add_and_need_flush(pvec, page))
- pagevec_lru_move_fn(pvec, lru_deactivate_fn);
+ fbatch = this_cpu_ptr(&lru_pvecs.lru_deactivate);
+ folio_batch_add_and_move(fbatch, folio, lru_deactivate_fn);
local_unlock(&lru_pvecs.lock);
}
}
@@ -896,7 +898,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
if (folio_batch_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
- pagevec_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
+ folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
pagevec_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
need_activate_page_drain(cpu) ||
need_mlock_page_drain(cpu) ||
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 07/22] mm/swap: Convert lru_lazyfree to a folio_batch
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (5 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 06/22] mm/swap: Convert lru_deactivate " Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 08/22] mm/swap: Convert activate_page " Matthew Wilcox (Oracle)
` (14 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Using folios instead of pages removes several calls to compound_head(),
shrinking the kernel by 1089 bytes of text.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 51 ++++++++++++++++++++++++++-------------------------
1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index c0323b312a46..f2d7b0c3bd54 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -64,7 +64,7 @@ struct lru_pvecs {
struct folio_batch lru_add;
struct folio_batch lru_deactivate_file;
struct folio_batch lru_deactivate;
- struct pagevec lru_lazyfree;
+ struct folio_batch lru_lazyfree;
#ifdef CONFIG_SMP
struct pagevec activate_page;
#endif
@@ -639,22 +639,22 @@ static void lru_deactivate_fn(struct lruvec *lruvec, struct folio *folio)
}
}
-static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec)
+static void lru_lazyfree_fn(struct lruvec *lruvec, struct folio *folio)
{
- if (PageAnon(page) && PageSwapBacked(page) &&
- !PageSwapCache(page) && !PageUnevictable(page)) {
- int nr_pages = thp_nr_pages(page);
+ if (folio_test_anon(folio) && folio_test_swapbacked(folio) &&
+ !folio_test_swapcache(folio) && !folio_test_unevictable(folio)) {
+ long nr_pages = folio_nr_pages(folio);
- del_page_from_lru_list(page, lruvec);
- ClearPageActive(page);
- ClearPageReferenced(page);
+ lruvec_del_folio(lruvec, folio);
+ folio_clear_active(folio);
+ folio_clear_referenced(folio);
/*
- * Lazyfree pages are clean anonymous pages. They have
- * PG_swapbacked flag cleared, to distinguish them from normal
- * anonymous pages
+ * Lazyfree folios are clean anonymous folios. They have
+ * the swapbacked flag cleared, to distinguish them from normal
+ * anonymous folios
*/
- ClearPageSwapBacked(page);
- add_page_to_lru_list(page, lruvec);
+ folio_clear_swapbacked(folio);
+ lruvec_add_folio(lruvec, folio);
__count_vm_events(PGLAZYFREE, nr_pages);
__count_memcg_events(lruvec_memcg(lruvec), PGLAZYFREE,
@@ -670,7 +670,6 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec)
void lru_add_drain_cpu(int cpu)
{
struct folio_batch *fbatch = &per_cpu(lru_pvecs.lru_add, cpu);
- struct pagevec *pvec;
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_add_fn);
@@ -694,9 +693,9 @@ void lru_add_drain_cpu(int cpu)
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_deactivate_fn);
- pvec = &per_cpu(lru_pvecs.lru_lazyfree, cpu);
- if (pagevec_count(pvec))
- pagevec_lru_move_fn(pvec, lru_lazyfree_fn);
+ fbatch = &per_cpu(lru_pvecs.lru_lazyfree, cpu);
+ if (folio_batch_count(fbatch))
+ folio_batch_move_lru(fbatch, lru_lazyfree_fn);
activate_page_drain(cpu);
}
@@ -759,15 +758,17 @@ void deactivate_page(struct page *page)
*/
void mark_page_lazyfree(struct page *page)
{
- if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) &&
- !PageSwapCache(page) && !PageUnevictable(page)) {
- struct pagevec *pvec;
+ struct folio *folio = page_folio(page);
+ if (folio_test_lru(folio) && folio_test_anon(folio) &&
+ folio_test_swapbacked(folio) && !folio_test_swapcache(folio) &&
+ !folio_test_unevictable(folio)) {
+ struct folio_batch *fbatch;
+
+ folio_get(folio);
local_lock(&lru_pvecs.lock);
- pvec = this_cpu_ptr(&lru_pvecs.lru_lazyfree);
- get_page(page);
- if (pagevec_add_and_need_flush(pvec, page))
- pagevec_lru_move_fn(pvec, lru_lazyfree_fn);
+ fbatch = this_cpu_ptr(&lru_pvecs.lru_lazyfree);
+ folio_batch_add_and_move(fbatch, folio, lru_lazyfree_fn);
local_unlock(&lru_pvecs.lock);
}
}
@@ -899,7 +900,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
- pagevec_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
+ folio_batch_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
need_activate_page_drain(cpu) ||
need_mlock_page_drain(cpu) ||
has_bh_in_lru(cpu, NULL)) {
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 08/22] mm/swap: Convert activate_page to a folio_batch
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (6 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 07/22] mm/swap: Convert lru_lazyfree " Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 09/22] mm/swap: Rename lru_pvecs to cpu_fbatches Matthew Wilcox (Oracle)
` (13 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Rename it to just 'activate', saving 696 bytes of text from removals
of compound_page() and the pagevec_lru_move_fn() infrastructure.
Inline need_activate_page_drain() into its only caller.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 81 +++++++++++--------------------------------------------
1 file changed, 16 insertions(+), 65 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index f2d7b0c3bd54..bba9ed25c56d 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -66,7 +66,7 @@ struct lru_pvecs {
struct folio_batch lru_deactivate;
struct folio_batch lru_lazyfree;
#ifdef CONFIG_SMP
- struct pagevec activate_page;
+ struct folio_batch activate;
#endif
};
static DEFINE_PER_CPU(struct lru_pvecs, lru_pvecs) = {
@@ -188,44 +188,6 @@ int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write,
}
EXPORT_SYMBOL_GPL(get_kernel_pages);
-static void pagevec_lru_move_fn(struct pagevec *pvec,
- void (*move_fn)(struct page *page, struct lruvec *lruvec))
-{
- int i;
- struct lruvec *lruvec = NULL;
- unsigned long flags = 0;
-
- for (i = 0; i < pagevec_count(pvec); i++) {
- struct page *page = pvec->pages[i];
- struct folio *folio = page_folio(page);
-
- /* block memcg migration during page moving between lru */
- if (!TestClearPageLRU(page))
- continue;
-
- lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
- (*move_fn)(page, lruvec);
-
- SetPageLRU(page);
- }
- if (lruvec)
- unlock_page_lruvec_irqrestore(lruvec, flags);
- release_pages(pvec->pages, pvec->nr);
- pagevec_reinit(pvec);
-}
-
-/* return true if pagevec needs to drain */
-static bool pagevec_add_and_need_flush(struct pagevec *pvec, struct page *page)
-{
- bool ret = false;
-
- if (!pagevec_add(pvec, page) || PageCompound(page) ||
- lru_cache_disabled())
- ret = true;
-
- return ret;
-}
-
typedef void (*move_fn_t)(struct lruvec *lruvec, struct folio *folio);
static void lru_add_fn(struct lruvec *lruvec, struct folio *folio)
@@ -380,7 +342,7 @@ void lru_note_cost_folio(struct folio *folio)
folio_nr_pages(folio));
}
-static void __folio_activate(struct folio *folio, struct lruvec *lruvec)
+static void folio_activate_fn(struct lruvec *lruvec, struct folio *folio)
{
if (!folio_test_active(folio) && !folio_test_unevictable(folio)) {
long nr_pages = folio_nr_pages(folio);
@@ -397,41 +359,30 @@ static void __folio_activate(struct folio *folio, struct lruvec *lruvec)
}
#ifdef CONFIG_SMP
-static void __activate_page(struct page *page, struct lruvec *lruvec)
+static void folio_activate_drain(int cpu)
{
- return __folio_activate(page_folio(page), lruvec);
-}
+ struct folio_batch *fbatch = &per_cpu(lru_pvecs.activate, cpu);
-static void activate_page_drain(int cpu)
-{
- struct pagevec *pvec = &per_cpu(lru_pvecs.activate_page, cpu);
-
- if (pagevec_count(pvec))
- pagevec_lru_move_fn(pvec, __activate_page);
-}
-
-static bool need_activate_page_drain(int cpu)
-{
- return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0;
+ if (folio_batch_count(fbatch))
+ folio_batch_move_lru(fbatch, folio_activate_fn);
}
static void folio_activate(struct folio *folio)
{
if (folio_test_lru(folio) && !folio_test_active(folio) &&
!folio_test_unevictable(folio)) {
- struct pagevec *pvec;
+ struct folio_batch *fbatch;
folio_get(folio);
local_lock(&lru_pvecs.lock);
- pvec = this_cpu_ptr(&lru_pvecs.activate_page);
- if (pagevec_add_and_need_flush(pvec, &folio->page))
- pagevec_lru_move_fn(pvec, __activate_page);
+ fbatch = this_cpu_ptr(&lru_pvecs.activate);
+ folio_batch_add_and_move(fbatch, folio, folio_activate_fn);
local_unlock(&lru_pvecs.lock);
}
}
#else
-static inline void activate_page_drain(int cpu)
+static inline void folio_activate_drain(int cpu)
{
}
@@ -441,7 +392,7 @@ static void folio_activate(struct folio *folio)
if (folio_test_clear_lru(folio)) {
lruvec = folio_lruvec_lock_irq(folio);
- __folio_activate(folio, lruvec);
+ folio_activate_fn(lruvec, folio);
unlock_page_lruvec_irq(lruvec);
folio_set_lru(folio);
}
@@ -500,9 +451,9 @@ void folio_mark_accessed(struct folio *folio)
*/
} else if (!folio_test_active(folio)) {
/*
- * If the page is on the LRU, queue it for activation via
- * lru_pvecs.activate_page. Otherwise, assume the page is on a
- * pagevec, mark it active and it'll be moved to the active
+ * If the folio is on the LRU, queue it for activation via
+ * lru_pvecs.activate. Otherwise, assume the folio is in a
+ * folio_batch, mark it active and it'll be moved to the active
* LRU on the next drain.
*/
if (folio_test_lru(folio))
@@ -697,7 +648,7 @@ void lru_add_drain_cpu(int cpu)
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_lazyfree_fn);
- activate_page_drain(cpu);
+ folio_activate_drain(cpu);
}
/**
@@ -901,7 +852,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
folio_batch_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
- need_activate_page_drain(cpu) ||
+ folio_batch_count(&per_cpu(lru_pvecs.activate, cpu)) ||
need_mlock_page_drain(cpu) ||
has_bh_in_lru(cpu, NULL)) {
INIT_WORK(work, lru_add_drain_per_cpu);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 09/22] mm/swap: Rename lru_pvecs to cpu_fbatches
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (7 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 08/22] mm/swap: Convert activate_page " Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 10/22] mm/swap: Pull the CPU conditional out of __lru_add_drain_all() Matthew Wilcox (Oracle)
` (12 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
No change to generated code, but this struct no longer contains any
pagevecs, and not all the folio batches it contains are lru.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 90 ++++++++++++++++++++++++++++---------------------------
1 file changed, 46 insertions(+), 44 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index bba9ed25c56d..e65a195c184b 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -56,10 +56,10 @@ static DEFINE_PER_CPU(struct lru_rotate, lru_rotate) = {
};
/*
- * The following struct pagevec are grouped together because they are protected
+ * The following folio batches are grouped together because they are protected
* by disabling preemption (and interrupts remain enabled).
*/
-struct lru_pvecs {
+struct cpu_fbatches {
local_lock_t lock;
struct folio_batch lru_add;
struct folio_batch lru_deactivate_file;
@@ -69,7 +69,7 @@ struct lru_pvecs {
struct folio_batch activate;
#endif
};
-static DEFINE_PER_CPU(struct lru_pvecs, lru_pvecs) = {
+static DEFINE_PER_CPU(struct cpu_fbatches, cpu_fbatches) = {
.lock = INIT_LOCAL_LOCK(lock),
};
@@ -361,7 +361,7 @@ static void folio_activate_fn(struct lruvec *lruvec, struct folio *folio)
#ifdef CONFIG_SMP
static void folio_activate_drain(int cpu)
{
- struct folio_batch *fbatch = &per_cpu(lru_pvecs.activate, cpu);
+ struct folio_batch *fbatch = &per_cpu(cpu_fbatches.activate, cpu);
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, folio_activate_fn);
@@ -374,10 +374,10 @@ static void folio_activate(struct folio *folio)
struct folio_batch *fbatch;
folio_get(folio);
- local_lock(&lru_pvecs.lock);
- fbatch = this_cpu_ptr(&lru_pvecs.activate);
+ local_lock(&cpu_fbatches.lock);
+ fbatch = this_cpu_ptr(&cpu_fbatches.activate);
folio_batch_add_and_move(fbatch, folio, folio_activate_fn);
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
}
}
@@ -404,8 +404,8 @@ static void __lru_cache_activate_folio(struct folio *folio)
struct folio_batch *fbatch;
int i;
- local_lock(&lru_pvecs.lock);
- fbatch = this_cpu_ptr(&lru_pvecs.lru_add);
+ local_lock(&cpu_fbatches.lock);
+ fbatch = this_cpu_ptr(&cpu_fbatches.lru_add);
/*
* Search backwards on the optimistic assumption that the folio being
@@ -426,7 +426,7 @@ static void __lru_cache_activate_folio(struct folio *folio)
}
}
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
}
/*
@@ -452,7 +452,7 @@ void folio_mark_accessed(struct folio *folio)
} else if (!folio_test_active(folio)) {
/*
* If the folio is on the LRU, queue it for activation via
- * lru_pvecs.activate. Otherwise, assume the folio is in a
+ * cpu_fbatches.activate. Otherwise, assume the folio is in a
* folio_batch, mark it active and it'll be moved to the active
* LRU on the next drain.
*/
@@ -474,7 +474,7 @@ EXPORT_SYMBOL(folio_mark_accessed);
*
* Queue the folio for addition to the LRU. The decision on whether
* to add the page to the [in]active [file|anon] list is deferred until the
- * pagevec is drained. This gives a chance for the caller of folio_add_lru()
+ * folio_batch is drained. This gives a chance for the caller of folio_add_lru()
* have the folio added to the active list using folio_mark_accessed().
*/
void folio_add_lru(struct folio *folio)
@@ -486,10 +486,10 @@ void folio_add_lru(struct folio *folio)
VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
folio_get(folio);
- local_lock(&lru_pvecs.lock);
- fbatch = this_cpu_ptr(&lru_pvecs.lru_add);
+ local_lock(&cpu_fbatches.lock);
+ fbatch = this_cpu_ptr(&cpu_fbatches.lru_add);
folio_batch_add_and_move(fbatch, folio, lru_add_fn);
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
}
EXPORT_SYMBOL(folio_add_lru);
@@ -614,13 +614,13 @@ static void lru_lazyfree_fn(struct lruvec *lruvec, struct folio *folio)
}
/*
- * Drain pages out of the cpu's pagevecs.
+ * Drain pages out of the cpu's folio_batch.
* Either "cpu" is the current CPU, and preemption has already been
* disabled; or "cpu" is being hot-unplugged, and is already dead.
*/
void lru_add_drain_cpu(int cpu)
{
- struct folio_batch *fbatch = &per_cpu(lru_pvecs.lru_add, cpu);
+ struct folio_batch *fbatch = &per_cpu(cpu_fbatches.lru_add, cpu);
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_add_fn);
@@ -636,15 +636,15 @@ void lru_add_drain_cpu(int cpu)
local_unlock_irqrestore(&lru_rotate.lock, flags);
}
- fbatch = &per_cpu(lru_pvecs.lru_deactivate_file, cpu);
+ fbatch = &per_cpu(cpu_fbatches.lru_deactivate_file, cpu);
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_deactivate_file_fn);
- fbatch = &per_cpu(lru_pvecs.lru_deactivate, cpu);
+ fbatch = &per_cpu(cpu_fbatches.lru_deactivate, cpu);
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_deactivate_fn);
- fbatch = &per_cpu(lru_pvecs.lru_lazyfree, cpu);
+ fbatch = &per_cpu(cpu_fbatches.lru_lazyfree, cpu);
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_lazyfree_fn);
@@ -670,10 +670,10 @@ void deactivate_file_folio(struct folio *folio)
return;
folio_get(folio);
- local_lock(&lru_pvecs.lock);
- fbatch = this_cpu_ptr(&lru_pvecs.lru_deactivate_file);
+ local_lock(&cpu_fbatches.lock);
+ fbatch = this_cpu_ptr(&cpu_fbatches.lru_deactivate_file);
folio_batch_add_and_move(fbatch, folio, lru_deactivate_file_fn);
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
}
/*
@@ -693,10 +693,10 @@ void deactivate_page(struct page *page)
struct folio_batch *fbatch;
folio_get(folio);
- local_lock(&lru_pvecs.lock);
- fbatch = this_cpu_ptr(&lru_pvecs.lru_deactivate);
+ local_lock(&cpu_fbatches.lock);
+ fbatch = this_cpu_ptr(&cpu_fbatches.lru_deactivate);
folio_batch_add_and_move(fbatch, folio, lru_deactivate_fn);
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
}
}
@@ -717,18 +717,18 @@ void mark_page_lazyfree(struct page *page)
struct folio_batch *fbatch;
folio_get(folio);
- local_lock(&lru_pvecs.lock);
- fbatch = this_cpu_ptr(&lru_pvecs.lru_lazyfree);
+ local_lock(&cpu_fbatches.lock);
+ fbatch = this_cpu_ptr(&cpu_fbatches.lru_lazyfree);
folio_batch_add_and_move(fbatch, folio, lru_lazyfree_fn);
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
}
}
void lru_add_drain(void)
{
- local_lock(&lru_pvecs.lock);
+ local_lock(&cpu_fbatches.lock);
lru_add_drain_cpu(smp_processor_id());
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
mlock_page_drain_local();
}
@@ -740,19 +740,19 @@ void lru_add_drain(void)
*/
static void lru_add_and_bh_lrus_drain(void)
{
- local_lock(&lru_pvecs.lock);
+ local_lock(&cpu_fbatches.lock);
lru_add_drain_cpu(smp_processor_id());
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
invalidate_bh_lrus_cpu();
mlock_page_drain_local();
}
void lru_add_drain_cpu_zone(struct zone *zone)
{
- local_lock(&lru_pvecs.lock);
+ local_lock(&cpu_fbatches.lock);
lru_add_drain_cpu(smp_processor_id());
drain_local_pages(zone);
- local_unlock(&lru_pvecs.lock);
+ local_unlock(&cpu_fbatches.lock);
mlock_page_drain_local();
}
@@ -797,8 +797,9 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
return;
/*
- * Guarantee pagevec counter stores visible by this CPU are visible to
- * other CPUs before loading the current drain generation.
+ * Guarantee folio_batch counter stores visible by this CPU
+ * are visible to other CPUs before loading the current drain
+ * generation.
*/
smp_mb();
@@ -824,8 +825,9 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
* (D) Increment global generation number
*
* Pairs with smp_load_acquire() at (B), outside of the critical
- * section. Use a full memory barrier to guarantee that the new global
- * drain generation number is stored before loading pagevec counters.
+ * section. Use a full memory barrier to guarantee that the
+ * new global drain generation number is stored before loading
+ * folio_batch counters.
*
* This pairing must be done here, before the for_each_online_cpu loop
* below which drains the page vectors.
@@ -847,12 +849,12 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
for_each_online_cpu(cpu) {
struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
- if (folio_batch_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
+ if (folio_batch_count(&per_cpu(cpu_fbatches.lru_add, cpu)) ||
data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
- folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
- folio_batch_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
- folio_batch_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
- folio_batch_count(&per_cpu(lru_pvecs.activate, cpu)) ||
+ folio_batch_count(&per_cpu(cpu_fbatches.lru_deactivate_file, cpu)) ||
+ folio_batch_count(&per_cpu(cpu_fbatches.lru_deactivate, cpu)) ||
+ folio_batch_count(&per_cpu(cpu_fbatches.lru_lazyfree, cpu)) ||
+ folio_batch_count(&per_cpu(cpu_fbatches.activate, cpu)) ||
need_mlock_page_drain(cpu) ||
has_bh_in_lru(cpu, NULL)) {
INIT_WORK(work, lru_add_drain_per_cpu);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 10/22] mm/swap: Pull the CPU conditional out of __lru_add_drain_all()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (8 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 09/22] mm/swap: Rename lru_pvecs to cpu_fbatches Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 11/22] mm/swap: Optimise lru_add_drain_cpu() Matthew Wilcox (Oracle)
` (11 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
The function is too long, so pull this complicated conditional out into
cpu_needs_drain(). This ends up shrinking the text by 14 bytes,
by allowing GCC to cache the result of calling per_cpu() instead of
relocating each lookup individually.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index e65a195c184b..7966aa6bdd3f 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -765,6 +765,21 @@ static void lru_add_drain_per_cpu(struct work_struct *dummy)
lru_add_and_bh_lrus_drain();
}
+static bool cpu_needs_drain(unsigned int cpu)
+{
+ struct cpu_fbatches *fbatches = &per_cpu(cpu_fbatches, cpu);
+
+ /* Check these in order of likelihood that they're not zero */
+ return folio_batch_count(&fbatches->lru_add) ||
+ data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
+ folio_batch_count(&fbatches->lru_deactivate_file) ||
+ folio_batch_count(&fbatches->lru_deactivate) ||
+ folio_batch_count(&fbatches->lru_lazyfree) ||
+ folio_batch_count(&fbatches->activate) ||
+ need_mlock_page_drain(cpu) ||
+ has_bh_in_lru(cpu, NULL);
+}
+
/*
* Doesn't need any cpu hotplug locking because we do rely on per-cpu
* kworkers being shut down before our page_alloc_cpu_dead callback is
@@ -849,14 +864,7 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
for_each_online_cpu(cpu) {
struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
- if (folio_batch_count(&per_cpu(cpu_fbatches.lru_add, cpu)) ||
- data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
- folio_batch_count(&per_cpu(cpu_fbatches.lru_deactivate_file, cpu)) ||
- folio_batch_count(&per_cpu(cpu_fbatches.lru_deactivate, cpu)) ||
- folio_batch_count(&per_cpu(cpu_fbatches.lru_lazyfree, cpu)) ||
- folio_batch_count(&per_cpu(cpu_fbatches.activate, cpu)) ||
- need_mlock_page_drain(cpu) ||
- has_bh_in_lru(cpu, NULL)) {
+ if (cpu_needs_drain(cpu)) {
INIT_WORK(work, lru_add_drain_per_cpu);
queue_work_on(cpu, mm_percpu_wq, work);
__cpumask_set_cpu(cpu, &has_work);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 11/22] mm/swap: Optimise lru_add_drain_cpu()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (9 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 10/22] mm/swap: Pull the CPU conditional out of __lru_add_drain_all() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 12/22] mm/swap: Convert try_to_free_swap to use a folio Matthew Wilcox (Oracle)
` (10 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Do the per-cpu dereferencing of the fbatches once which saves 14 bytes
of text and several percpu relocations.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 7966aa6bdd3f..5ea6ae795f0d 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -620,7 +620,8 @@ static void lru_lazyfree_fn(struct lruvec *lruvec, struct folio *folio)
*/
void lru_add_drain_cpu(int cpu)
{
- struct folio_batch *fbatch = &per_cpu(cpu_fbatches.lru_add, cpu);
+ struct cpu_fbatches *fbatches = &per_cpu(cpu_fbatches, cpu);
+ struct folio_batch *fbatch = &fbatches->lru_add;
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_add_fn);
@@ -636,15 +637,15 @@ void lru_add_drain_cpu(int cpu)
local_unlock_irqrestore(&lru_rotate.lock, flags);
}
- fbatch = &per_cpu(cpu_fbatches.lru_deactivate_file, cpu);
+ fbatch = &fbatches->lru_deactivate_file;
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_deactivate_file_fn);
- fbatch = &per_cpu(cpu_fbatches.lru_deactivate, cpu);
+ fbatch = &fbatches->lru_deactivate;
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_deactivate_fn);
- fbatch = &per_cpu(cpu_fbatches.lru_lazyfree, cpu);
+ fbatch = &fbatches->lru_lazyfree;
if (folio_batch_count(fbatch))
folio_batch_move_lru(fbatch, lru_lazyfree_fn);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 12/22] mm/swap: Convert try_to_free_swap to use a folio
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (10 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 11/22] mm/swap: Optimise lru_add_drain_cpu() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 13/22] mm/swap: Convert release_pages to use a folio internally Matthew Wilcox (Oracle)
` (9 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Save a few calls to compound_head by converting the passed page to
a folio. Reduces kernel text size by 74 bytes.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swapfile.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 3fa26f6971e9..4ac6a6c876d6 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1568,16 +1568,15 @@ static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
return ret;
}
-static bool page_swapped(struct page *page)
+static bool folio_swapped(struct folio *folio)
{
swp_entry_t entry;
struct swap_info_struct *si;
- if (!IS_ENABLED(CONFIG_THP_SWAP) || likely(!PageTransCompound(page)))
- return page_swapcount(page) != 0;
+ if (!IS_ENABLED(CONFIG_THP_SWAP) || likely(!folio_test_large(folio)))
+ return page_swapcount(&folio->page) != 0;
- page = compound_head(page);
- entry.val = page_private(page);
+ entry = folio_swap_entry(folio);
si = _swap_info_get(entry);
if (si)
return swap_page_trans_huge_swapped(si, entry);
@@ -1590,13 +1589,14 @@ static bool page_swapped(struct page *page)
*/
int try_to_free_swap(struct page *page)
{
- VM_BUG_ON_PAGE(!PageLocked(page), page);
+ struct folio *folio = page_folio(page);
+ VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
- if (!PageSwapCache(page))
+ if (!folio_test_swapcache(folio))
return 0;
- if (PageWriteback(page))
+ if (folio_test_writeback(folio))
return 0;
- if (page_swapped(page))
+ if (folio_swapped(folio))
return 0;
/*
@@ -1617,9 +1617,8 @@ int try_to_free_swap(struct page *page)
if (pm_suspended_storage())
return 0;
- page = compound_head(page);
- delete_from_swap_cache(page);
- SetPageDirty(page);
+ delete_from_swap_cache(&folio->page);
+ folio_set_dirty(folio);
return 1;
}
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 13/22] mm/swap: Convert release_pages to use a folio internally
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (11 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 12/22] mm/swap: Convert try_to_free_swap to use a folio Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 14/22] mm/swap: Convert put_pages_list to use folios Matthew Wilcox (Oracle)
` (8 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
This function was already calling compound_head(), but now it can
cache the result of calling compound_head() and avoid calling it again.
Saves 299 bytes of text by avoiding various calls to compound_page()
and avoiding checks of PageTail.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 5ea6ae795f0d..15ed7584ccb9 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -941,8 +941,7 @@ void release_pages(struct page **pages, int nr)
unsigned int lock_batch;
for (i = 0; i < nr; i++) {
- struct page *page = pages[i];
- struct folio *folio = page_folio(page);
+ struct folio *folio = page_folio(pages[i]);
/*
* Make sure the IRQ-safe lock-holding time does not get
@@ -954,35 +953,34 @@ void release_pages(struct page **pages, int nr)
lruvec = NULL;
}
- page = &folio->page;
- if (is_huge_zero_page(page))
+ if (is_huge_zero_page(&folio->page))
continue;
- if (is_zone_device_page(page)) {
+ if (folio_is_zone_device(folio)) {
if (lruvec) {
unlock_page_lruvec_irqrestore(lruvec, flags);
lruvec = NULL;
}
- if (put_devmap_managed_page(page))
+ if (put_devmap_managed_page(&folio->page))
continue;
- if (put_page_testzero(page))
- free_zone_device_page(page);
+ if (folio_put_testzero(folio))
+ free_zone_device_page(&folio->page);
continue;
}
- if (!put_page_testzero(page))
+ if (!folio_put_testzero(folio))
continue;
- if (PageCompound(page)) {
+ if (folio_test_large(folio)) {
if (lruvec) {
unlock_page_lruvec_irqrestore(lruvec, flags);
lruvec = NULL;
}
- __put_compound_page(page);
+ __put_compound_page(&folio->page);
continue;
}
- if (PageLRU(page)) {
+ if (folio_test_lru(folio)) {
struct lruvec *prev_lruvec = lruvec;
lruvec = folio_lruvec_relock_irqsave(folio, lruvec,
@@ -990,8 +988,8 @@ void release_pages(struct page **pages, int nr)
if (prev_lruvec != lruvec)
lock_batch = 0;
- del_page_from_lru_list(page, lruvec);
- __clear_page_lru_flags(page);
+ lruvec_del_folio(lruvec, folio);
+ __folio_clear_lru_flags(folio);
}
/*
@@ -1000,13 +998,13 @@ void release_pages(struct page **pages, int nr)
* found set here. This does not indicate a problem, unless
* "unevictable_pgs_cleared" appears worryingly large.
*/
- if (unlikely(PageMlocked(page))) {
- __ClearPageMlocked(page);
- dec_zone_page_state(page, NR_MLOCK);
+ if (unlikely(folio_test_mlocked(folio))) {
+ __folio_clear_mlocked(folio);
+ zone_stat_sub_folio(folio, NR_MLOCK);
count_vm_event(UNEVICTABLE_PGCLEARED);
}
- list_add(&page->lru, &pages_to_free);
+ list_add(&folio->lru, &pages_to_free);
}
if (lruvec)
unlock_page_lruvec_irqrestore(lruvec, flags);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 14/22] mm/swap: Convert put_pages_list to use folios
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (12 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 13/22] mm/swap: Convert release_pages to use a folio internally Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 15/22] mm/swap: Convert __put_page() to __folio_put() Matthew Wilcox (Oracle)
` (7 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Pages linked through the LRU list cannot be tail pages as ->compound_head
is in a union with one of the words of the list_head, and they cannot
be ZONE_DEVICE pages as ->pgmap is in a union with the same word.
Saves 60 bytes of text by removing a call to page_is_fake_head().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 15ed7584ccb9..3696dfbff136 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -138,19 +138,19 @@ EXPORT_SYMBOL(__put_page);
*/
void put_pages_list(struct list_head *pages)
{
- struct page *page, *next;
+ struct folio *folio, *next;
- list_for_each_entry_safe(page, next, pages, lru) {
- if (!put_page_testzero(page)) {
- list_del(&page->lru);
+ list_for_each_entry_safe(folio, next, pages, lru) {
+ if (!folio_put_testzero(folio)) {
+ list_del(&folio->lru);
continue;
}
- if (PageHead(page)) {
- list_del(&page->lru);
- __put_compound_page(page);
+ if (folio_test_large(folio)) {
+ list_del(&folio->lru);
+ __put_compound_page(&folio->page);
continue;
}
- /* Cannot be PageLRU because it's passed to us using the lru */
+ /* LRU flag must be clear because it's passed using the lru */
}
free_unref_page_list(pages);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 15/22] mm/swap: Convert __put_page() to __folio_put()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (13 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 14/22] mm/swap: Convert put_pages_list to use folios Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 16/22] mm/swap: Convert __put_single_page() to __folio_put_small() Matthew Wilcox (Oracle)
` (6 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Saves 11 bytes of text by removing a check of PageTail.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/linux/mm.h | 6 +++---
mm/swap.c | 14 +++++++-------
net/core/page_pool.c | 2 +-
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 07a1998c3621..764dc0fdae5e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -886,7 +886,7 @@ static inline struct folio *virt_to_folio(const void *x)
return page_folio(page);
}
-void __put_page(struct page *page);
+void __folio_put(struct folio *folio);
void put_pages_list(struct list_head *pages);
@@ -1228,7 +1228,7 @@ static inline __must_check bool try_get_page(struct page *page)
static inline void folio_put(struct folio *folio)
{
if (folio_put_testzero(folio))
- __put_page(&folio->page);
+ __folio_put(folio);
}
/**
@@ -1248,7 +1248,7 @@ static inline void folio_put(struct folio *folio)
static inline void folio_put_refs(struct folio *folio, int refs)
{
if (folio_ref_sub_and_test(folio, refs))
- __put_page(&folio->page);
+ __folio_put(folio);
}
void release_pages(struct page **pages, int nr);
diff --git a/mm/swap.c b/mm/swap.c
index 3696dfbff136..0ab7a032a766 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -119,16 +119,16 @@ static void __put_compound_page(struct page *page)
destroy_compound_page(page);
}
-void __put_page(struct page *page)
+void __folio_put(struct folio *folio)
{
- if (unlikely(is_zone_device_page(page)))
- free_zone_device_page(page);
- else if (unlikely(PageCompound(page)))
- __put_compound_page(page);
+ if (unlikely(folio_is_zone_device(folio)))
+ free_zone_device_page(&folio->page);
+ else if (unlikely(folio_test_large(folio)))
+ __put_compound_page(&folio->page);
else
- __put_single_page(page);
+ __put_single_page(&folio->page);
}
-EXPORT_SYMBOL(__put_page);
+EXPORT_SYMBOL(__folio_put);
/**
* put_pages_list() - release a list of pages
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index f18e6e771993..db70e94c8df2 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -16,7 +16,7 @@
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/page-flags.h>
-#include <linux/mm.h> /* for __put_page() */
+#include <linux/mm.h> /* for put_page() */
#include <linux/poison.h>
#include <linux/ethtool.h>
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 16/22] mm/swap: Convert __put_single_page() to __folio_put_small()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (14 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 15/22] mm/swap: Convert __put_page() to __folio_put() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 17/22] mm/swap: Convert __put_compound_page() to __folio_put_large() Matthew Wilcox (Oracle)
` (5 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
Saves 56 bytes of text by removing a call to compound_head().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 0ab7a032a766..a7097eaceafb 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -99,11 +99,11 @@ static void __page_cache_release(struct page *page)
}
}
-static void __put_single_page(struct page *page)
+static void __folio_put_small(struct folio *folio)
{
- __page_cache_release(page);
- mem_cgroup_uncharge(page_folio(page));
- free_unref_page(page, 0);
+ __page_cache_release(&folio->page);
+ mem_cgroup_uncharge(folio);
+ free_unref_page(&folio->page, 0);
}
static void __put_compound_page(struct page *page)
@@ -126,7 +126,7 @@ void __folio_put(struct folio *folio)
else if (unlikely(folio_test_large(folio)))
__put_compound_page(&folio->page);
else
- __put_single_page(&folio->page);
+ __folio_put_small(folio);
}
EXPORT_SYMBOL(__folio_put);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 17/22] mm/swap: Convert __put_compound_page() to __folio_put_large()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (15 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 16/22] mm/swap: Convert __put_single_page() to __folio_put_small() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 18/22] mm/swap: Convert __page_cache_release() to use a folio Matthew Wilcox (Oracle)
` (4 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
All the callers now have a folio, so pass it in. This doesn't
save any text, but it does save a call to compound_head() as
folio_test_hugetlb() does not contain a call like PageHuge() does.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index a7097eaceafb..2570d18e71a5 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -106,7 +106,7 @@ static void __folio_put_small(struct folio *folio)
free_unref_page(&folio->page, 0);
}
-static void __put_compound_page(struct page *page)
+static void __folio_put_large(struct folio *folio)
{
/*
* __page_cache_release() is supposed to be called for thp, not for
@@ -114,9 +114,9 @@ static void __put_compound_page(struct page *page)
* (it's never listed to any LRU lists) and no memcg routines should
* be called for hugetlb (it has a separate hugetlb_cgroup.)
*/
- if (!PageHuge(page))
- __page_cache_release(page);
- destroy_compound_page(page);
+ if (!folio_test_hugetlb(folio))
+ __page_cache_release(&folio->page);
+ destroy_compound_page(&folio->page);
}
void __folio_put(struct folio *folio)
@@ -124,7 +124,7 @@ void __folio_put(struct folio *folio)
if (unlikely(folio_is_zone_device(folio)))
free_zone_device_page(&folio->page);
else if (unlikely(folio_test_large(folio)))
- __put_compound_page(&folio->page);
+ __folio_put_large(folio);
else
__folio_put_small(folio);
}
@@ -147,7 +147,7 @@ void put_pages_list(struct list_head *pages)
}
if (folio_test_large(folio)) {
list_del(&folio->lru);
- __put_compound_page(&folio->page);
+ __folio_put_large(folio);
continue;
}
/* LRU flag must be clear because it's passed using the lru */
@@ -976,7 +976,7 @@ void release_pages(struct page **pages, int nr)
unlock_page_lruvec_irqrestore(lruvec, flags);
lruvec = NULL;
}
- __put_compound_page(&folio->page);
+ __folio_put_large(folio);
continue;
}
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 18/22] mm/swap: Convert __page_cache_release() to use a folio
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (16 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 17/22] mm/swap: Convert __put_compound_page() to __folio_put_large() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 19/22] mm: Convert destroy_compound_page() to destroy_large_folio() Matthew Wilcox (Oracle)
` (3 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
All the callers now have a folio. Saves several calls to compound_head,
totalling 502 bytes of text.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.c | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/mm/swap.c b/mm/swap.c
index 2570d18e71a5..f309694d9f84 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -77,31 +77,30 @@ static DEFINE_PER_CPU(struct cpu_fbatches, cpu_fbatches) = {
* This path almost never happens for VM activity - pages are normally freed
* via pagevecs. But it gets used by networking - and for compound pages.
*/
-static void __page_cache_release(struct page *page)
+static void __page_cache_release(struct folio *folio)
{
- if (PageLRU(page)) {
- struct folio *folio = page_folio(page);
+ if (folio_test_lru(folio)) {
struct lruvec *lruvec;
unsigned long flags;
lruvec = folio_lruvec_lock_irqsave(folio, &flags);
- del_page_from_lru_list(page, lruvec);
- __clear_page_lru_flags(page);
+ lruvec_del_folio(lruvec, folio);
+ __folio_clear_lru_flags(folio);
unlock_page_lruvec_irqrestore(lruvec, flags);
}
- /* See comment on PageMlocked in release_pages() */
- if (unlikely(PageMlocked(page))) {
- int nr_pages = thp_nr_pages(page);
+ /* See comment on folio_test_mlocked in release_pages() */
+ if (unlikely(folio_test_mlocked(folio))) {
+ long nr_pages = folio_nr_pages(folio);
- __ClearPageMlocked(page);
- mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages);
+ __folio_clear_mlocked(folio);
+ zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
}
}
static void __folio_put_small(struct folio *folio)
{
- __page_cache_release(&folio->page);
+ __page_cache_release(folio);
mem_cgroup_uncharge(folio);
free_unref_page(&folio->page, 0);
}
@@ -115,7 +114,7 @@ static void __folio_put_large(struct folio *folio)
* be called for hugetlb (it has a separate hugetlb_cgroup.)
*/
if (!folio_test_hugetlb(folio))
- __page_cache_release(&folio->page);
+ __page_cache_release(folio);
destroy_compound_page(&folio->page);
}
@@ -199,14 +198,14 @@ static void lru_add_fn(struct lruvec *lruvec, struct folio *folio)
/*
* Is an smp_mb__after_atomic() still required here, before
- * folio_evictable() tests PageMlocked, to rule out the possibility
+ * folio_evictable() tests the mlocked flag, to rule out the possibility
* of stranding an evictable folio on an unevictable LRU? I think
- * not, because __munlock_page() only clears PageMlocked while the LRU
- * lock is held.
+ * not, because __munlock_page() only clears the mlocked flag
+ * while the LRU lock is held.
*
* (That is not true of __page_cache_release(), and not necessarily
- * true of release_pages(): but those only clear PageMlocked after
- * put_page_testzero() has excluded any other users of the page.)
+ * true of release_pages(): but those only clear the mlocked flag after
+ * folio_put_testzero() has excluded any other users of the folio.)
*/
if (folio_evictable(folio)) {
if (was_unevictable)
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 19/22] mm: Convert destroy_compound_page() to destroy_large_folio()
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (17 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 18/22] mm/swap: Convert __page_cache_release() to use a folio Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 20/22] mm: Convert page_swap_flags to folio_swap_flags Matthew Wilcox (Oracle)
` (2 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
All callers now have a folio, so push the folio->page conversion
down to this function.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/linux/mm.h | 8 +++++---
mm/swap.c | 2 +-
mm/vmscan.c | 4 ++--
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 764dc0fdae5e..f99e49c4d36a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -923,10 +923,12 @@ static inline void set_compound_page_dtor(struct page *page,
page[1].compound_dtor = compound_dtor;
}
-static inline void destroy_compound_page(struct page *page)
+static inline void destroy_large_folio(struct folio *folio)
{
- VM_BUG_ON_PAGE(page[1].compound_dtor >= NR_COMPOUND_DTORS, page);
- compound_page_dtors[page[1].compound_dtor](page);
+ enum compound_dtor_id dtor = folio_page(folio, 1)->compound_dtor;
+
+ VM_BUG_ON_FOLIO(dtor >= NR_COMPOUND_DTORS, folio);
+ compound_page_dtors[dtor](&folio->page);
}
static inline int head_compound_pincount(struct page *head)
diff --git a/mm/swap.c b/mm/swap.c
index f309694d9f84..9cee7f6a3809 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -115,7 +115,7 @@ static void __folio_put_large(struct folio *folio)
*/
if (!folio_test_hugetlb(folio))
__page_cache_release(folio);
- destroy_compound_page(&folio->page);
+ destroy_large_folio(folio);
}
void __folio_put(struct folio *folio)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 6ba0fdf1dd0a..135f9306fe1e 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1985,7 +1985,7 @@ static unsigned int shrink_page_list(struct list_head *page_list,
* appear not as the counts should be low
*/
if (unlikely(folio_test_large(folio)))
- destroy_compound_page(&folio->page);
+ destroy_large_folio(folio);
else
list_add(&folio->lru, &free_pages);
continue;
@@ -2354,7 +2354,7 @@ static unsigned int move_pages_to_lru(struct lruvec *lruvec,
if (unlikely(folio_test_large(folio))) {
spin_unlock_irq(&lruvec->lru_lock);
- destroy_compound_page(&folio->page);
+ destroy_large_folio(folio);
spin_lock_irq(&lruvec->lru_lock);
} else
list_add(&folio->lru, &folios_to_free);
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 20/22] mm: Convert page_swap_flags to folio_swap_flags
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (18 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 19/22] mm: Convert destroy_compound_page() to destroy_large_folio() Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 21/22] mm/swap: Convert delete_from_swap_cache() to take a folio Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 22/22] mm/swap: Convert __delete_from_swap_cache() to " Matthew Wilcox (Oracle)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
The only caller already has a folio, so push the folio->page conversion
down a level.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.h | 6 +++---
mm/vmscan.c | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/mm/swap.h b/mm/swap.h
index 0193797b0c92..85453110be8e 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -61,9 +61,9 @@ struct page *swap_cluster_readahead(swp_entry_t entry, gfp_t flag,
struct page *swapin_readahead(swp_entry_t entry, gfp_t flag,
struct vm_fault *vmf);
-static inline unsigned int page_swap_flags(struct page *page)
+static inline unsigned int folio_swap_flags(struct folio *folio)
{
- return page_swap_info(page)->flags;
+ return page_swap_info(&folio->page)->flags;
}
#else /* CONFIG_SWAP */
struct swap_iocb;
@@ -149,7 +149,7 @@ static inline void clear_shadow_from_swap_cache(int type, unsigned long begin,
{
}
-static inline unsigned int page_swap_flags(struct page *page)
+static inline unsigned int folio_swap_flags(struct folio *folio)
{
return 0;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 135f9306fe1e..1256d6b51b67 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1572,7 +1572,7 @@ static bool may_enter_fs(struct folio *folio, gfp_t gfp_mask)
* but that will never affect SWP_FS_OPS, so the data_race
* is safe.
*/
- return !data_race(page_swap_flags(&folio->page) & SWP_FS_OPS);
+ return !data_race(folio_swap_flags(folio) & SWP_FS_OPS);
}
/*
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 21/22] mm/swap: Convert delete_from_swap_cache() to take a folio
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (19 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 20/22] mm: Convert page_swap_flags to folio_swap_flags Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 22/22] mm/swap: Convert __delete_from_swap_cache() to " Matthew Wilcox (Oracle)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
All but one caller already has a folio, so convert it to use a folio.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/memory-failure.c | 5 +++--
mm/shmem.c | 4 ++--
mm/swap.h | 4 ++--
mm/swap_state.c | 16 ++++++++--------
mm/swapfile.c | 2 +-
5 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index bc031939cf39..bd0e15b4876a 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1049,12 +1049,13 @@ static int me_swapcache_dirty(struct page_state *ps, struct page *p)
static int me_swapcache_clean(struct page_state *ps, struct page *p)
{
+ struct folio *folio = page_folio(p);
int ret;
- delete_from_swap_cache(p);
+ delete_from_swap_cache(folio);
ret = delete_from_lru_cache(p) ? MF_FAILED : MF_RECOVERED;
- unlock_page(p);
+ folio_unlock(folio);
if (has_extra_refcount(ps, p, false))
ret = MF_FAILED;
diff --git a/mm/shmem.c b/mm/shmem.c
index 133c67057d41..7331ed1be014 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1690,7 +1690,7 @@ static void shmem_set_folio_swapin_error(struct inode *inode, pgoff_t index,
return;
folio_wait_writeback(folio);
- delete_from_swap_cache(&folio->page);
+ delete_from_swap_cache(folio);
spin_lock_irq(&info->lock);
/*
* Don't treat swapin error folio as alloced. Otherwise inode->i_blocks won't
@@ -1788,7 +1788,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
if (sgp == SGP_WRITE)
folio_mark_accessed(folio);
- delete_from_swap_cache(&folio->page);
+ delete_from_swap_cache(folio);
folio_mark_dirty(folio);
swap_free(swap);
diff --git a/mm/swap.h b/mm/swap.h
index 85453110be8e..3684f7f4eac9 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -38,7 +38,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry,
gfp_t gfp, void **shadowp);
void __delete_from_swap_cache(struct page *page,
swp_entry_t entry, void *shadow);
-void delete_from_swap_cache(struct page *page);
+void delete_from_swap_cache(struct folio *folio);
void clear_shadow_from_swap_cache(int type, unsigned long begin,
unsigned long end);
void free_swap_cache(struct page *page);
@@ -140,7 +140,7 @@ static inline void __delete_from_swap_cache(struct page *page,
{
}
-static inline void delete_from_swap_cache(struct page *page)
+static inline void delete_from_swap_cache(struct folio *folio)
{
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 41c6a6053d5c..b9464542c064 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -222,22 +222,22 @@ bool add_to_swap(struct folio *folio)
}
/*
- * This must be called only on pages that have
+ * This must be called only on folios that have
* been verified to be in the swap cache and locked.
- * It will never put the page into the free list,
- * the caller has a reference on the page.
+ * It will never put the folio into the free list,
+ * the caller has a reference on the folio.
*/
-void delete_from_swap_cache(struct page *page)
+void delete_from_swap_cache(struct folio *folio)
{
- swp_entry_t entry = { .val = page_private(page) };
+ swp_entry_t entry = folio_swap_entry(folio);
struct address_space *address_space = swap_address_space(entry);
xa_lock_irq(&address_space->i_pages);
- __delete_from_swap_cache(page, entry, NULL);
+ __delete_from_swap_cache(&folio->page, entry, NULL);
xa_unlock_irq(&address_space->i_pages);
- put_swap_page(page, entry);
- page_ref_sub(page, thp_nr_pages(page));
+ put_swap_page(&folio->page, entry);
+ folio_ref_sub(folio, folio_nr_pages(folio));
}
void clear_shadow_from_swap_cache(int type, unsigned long begin,
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 4ac6a6c876d6..91eab0223d9e 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1617,7 +1617,7 @@ int try_to_free_swap(struct page *page)
if (pm_suspended_storage())
return 0;
- delete_from_swap_cache(&folio->page);
+ delete_from_swap_cache(folio);
folio_set_dirty(folio);
return 1;
}
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 22/22] mm/swap: Convert __delete_from_swap_cache() to a folio
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
` (20 preceding siblings ...)
2022-06-17 17:50 ` [PATCH 21/22] mm/swap: Convert delete_from_swap_cache() to take a folio Matthew Wilcox (Oracle)
@ 2022-06-17 17:50 ` Matthew Wilcox (Oracle)
21 siblings, 0 replies; 23+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-17 17:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: Matthew Wilcox (Oracle), linux-mm
All callers now have a folio, so convert the entire function to operate
on folios.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
mm/swap.h | 4 ++--
mm/swap_state.c | 25 +++++++++++++------------
mm/vmscan.c | 2 +-
3 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/mm/swap.h b/mm/swap.h
index 3684f7f4eac9..fa0816af4712 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -36,7 +36,7 @@ bool add_to_swap(struct folio *folio);
void *get_shadow_from_swap_cache(swp_entry_t entry);
int add_to_swap_cache(struct page *page, swp_entry_t entry,
gfp_t gfp, void **shadowp);
-void __delete_from_swap_cache(struct page *page,
+void __delete_from_swap_cache(struct folio *folio,
swp_entry_t entry, void *shadow);
void delete_from_swap_cache(struct folio *folio);
void clear_shadow_from_swap_cache(int type, unsigned long begin,
@@ -135,7 +135,7 @@ static inline int add_to_swap_cache(struct page *page, swp_entry_t entry,
return -1;
}
-static inline void __delete_from_swap_cache(struct page *page,
+static inline void __delete_from_swap_cache(struct folio *folio,
swp_entry_t entry, void *shadow)
{
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index b9464542c064..e166051566f4 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -133,31 +133,32 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry,
}
/*
- * This must be called only on pages that have
+ * This must be called only on folios that have
* been verified to be in the swap cache.
*/
-void __delete_from_swap_cache(struct page *page,
+void __delete_from_swap_cache(struct folio *folio,
swp_entry_t entry, void *shadow)
{
struct address_space *address_space = swap_address_space(entry);
- int i, nr = thp_nr_pages(page);
+ int i;
+ long nr = folio_nr_pages(folio);
pgoff_t idx = swp_offset(entry);
XA_STATE(xas, &address_space->i_pages, idx);
- VM_BUG_ON_PAGE(!PageLocked(page), page);
- VM_BUG_ON_PAGE(!PageSwapCache(page), page);
- VM_BUG_ON_PAGE(PageWriteback(page), page);
+ VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
+ VM_BUG_ON_FOLIO(!folio_test_swapcache(folio), folio);
+ VM_BUG_ON_FOLIO(folio_test_writeback(folio), folio);
for (i = 0; i < nr; i++) {
void *entry = xas_store(&xas, shadow);
- VM_BUG_ON_PAGE(entry != page, entry);
- set_page_private(page + i, 0);
+ VM_BUG_ON_FOLIO(entry != folio, folio);
+ set_page_private(folio_page(folio, i), 0);
xas_next(&xas);
}
- ClearPageSwapCache(page);
+ folio_clear_swapcache(folio);
address_space->nrpages -= nr;
- __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, -nr);
- __mod_lruvec_page_state(page, NR_SWAPCACHE, -nr);
+ __node_stat_mod_folio(folio, NR_FILE_PAGES, -nr);
+ __lruvec_stat_mod_folio(folio, NR_SWAPCACHE, -nr);
}
/**
@@ -233,7 +234,7 @@ void delete_from_swap_cache(struct folio *folio)
struct address_space *address_space = swap_address_space(entry);
xa_lock_irq(&address_space->i_pages);
- __delete_from_swap_cache(&folio->page, entry, NULL);
+ __delete_from_swap_cache(folio, entry, NULL);
xa_unlock_irq(&address_space->i_pages);
put_swap_page(&folio->page, entry);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1256d6b51b67..6a5c34dee00a 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1329,7 +1329,7 @@ static int __remove_mapping(struct address_space *mapping, struct folio *folio,
mem_cgroup_swapout(folio, swap);
if (reclaimed && !mapping_exiting(mapping))
shadow = workingset_eviction(folio, target_memcg);
- __delete_from_swap_cache(&folio->page, swap, shadow);
+ __delete_from_swap_cache(folio, swap, shadow);
xa_unlock_irq(&mapping->i_pages);
put_swap_page(&folio->page, swap);
} else {
--
2.35.1
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2022-06-17 17:50 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-17 17:49 [PATCH 00/22] Convert the swap code to be more folio-based Matthew Wilcox (Oracle)
2022-06-17 17:49 ` [PATCH 01/22] mm: Add folios_put() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 02/22] mm/swap: Add folio_batch_move_lru() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 03/22] mm/swap: Make __pagevec_lru_add static Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 04/22] mm/swap: Convert lru_add to a folio_batch Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 05/22] mm/swap: Convert lru_deactivate_file " Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 06/22] mm/swap: Convert lru_deactivate " Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 07/22] mm/swap: Convert lru_lazyfree " Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 08/22] mm/swap: Convert activate_page " Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 09/22] mm/swap: Rename lru_pvecs to cpu_fbatches Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 10/22] mm/swap: Pull the CPU conditional out of __lru_add_drain_all() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 11/22] mm/swap: Optimise lru_add_drain_cpu() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 12/22] mm/swap: Convert try_to_free_swap to use a folio Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 13/22] mm/swap: Convert release_pages to use a folio internally Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 14/22] mm/swap: Convert put_pages_list to use folios Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 15/22] mm/swap: Convert __put_page() to __folio_put() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 16/22] mm/swap: Convert __put_single_page() to __folio_put_small() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 17/22] mm/swap: Convert __put_compound_page() to __folio_put_large() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 18/22] mm/swap: Convert __page_cache_release() to use a folio Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 19/22] mm: Convert destroy_compound_page() to destroy_large_folio() Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 20/22] mm: Convert page_swap_flags to folio_swap_flags Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 21/22] mm/swap: Convert delete_from_swap_cache() to take a folio Matthew Wilcox (Oracle)
2022-06-17 17:50 ` [PATCH 22/22] mm/swap: Convert __delete_from_swap_cache() to " Matthew Wilcox (Oracle)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox