020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. From 6f315879ad750391a0b1fab8c9170bc054a5f5d7 Mon Sep 17 00:00:00 2001
  2. From: Yu Zhao <[email protected]>
  3. Date: Tue, 15 Nov 2022 18:38:07 -0700
  4. Subject: [PATCH 14/29] mm: multi-gen LRU: retry pages written back while
  5. isolated
  6. The page reclaim isolates a batch of pages from the tail of one of the
  7. LRU lists and works on those pages one by one. For a suitable
  8. swap-backed page, if the swap device is async, it queues that page for
  9. writeback. After the page reclaim finishes an entire batch, it puts back
  10. the pages it queued for writeback to the head of the original LRU list.
  11. In the meantime, the page writeback flushes the queued pages also by
  12. batches. Its batching logic is independent from that of the page reclaim.
  13. For each of the pages it writes back, the page writeback calls
  14. rotate_reclaimable_page() which tries to rotate a page to the tail.
  15. rotate_reclaimable_page() only works for a page after the page reclaim
  16. has put it back. If an async swap device is fast enough, the page
  17. writeback can finish with that page while the page reclaim is still
  18. working on the rest of the batch containing it. In this case, that page
  19. will remain at the head and the page reclaim will not retry it before
  20. reaching there.
  21. This patch adds a retry to evict_pages(). After evict_pages() has
  22. finished an entire batch and before it puts back pages it cannot free
  23. immediately, it retries those that may have missed the rotation.
  24. Before this patch, ~60% of pages swapped to an Intel Optane missed
  25. rotate_reclaimable_page(). After this patch, ~99% of missed pages were
  26. reclaimed upon retry.
  27. This problem affects relatively slow async swap devices like Samsung 980
  28. Pro much less and does not affect sync swap devices like zram or zswap at
  29. all.
  30. Link: https://lkml.kernel.org/r/[email protected]
  31. Fixes: ac35a4902374 ("mm: multi-gen LRU: minimal implementation")
  32. Signed-off-by: Yu Zhao <[email protected]>
  33. Cc: "Yin, Fengwei" <[email protected]>
  34. Signed-off-by: Andrew Morton <[email protected]>
  35. ---
  36. mm/vmscan.c | 48 +++++++++++++++++++++++++++++++++++++-----------
  37. 1 file changed, 37 insertions(+), 11 deletions(-)
  38. --- a/mm/vmscan.c
  39. +++ b/mm/vmscan.c
  40. @@ -4723,10 +4723,13 @@ static int evict_pages(struct lruvec *lr
  41. int scanned;
  42. int reclaimed;
  43. LIST_HEAD(list);
  44. + LIST_HEAD(clean);
  45. struct page *page;
  46. + struct page *next;
  47. enum vm_event_item item;
  48. struct reclaim_stat stat;
  49. struct lru_gen_mm_walk *walk;
  50. + bool skip_retry = false;
  51. struct mem_cgroup *memcg = lruvec_memcg(lruvec);
  52. struct pglist_data *pgdat = lruvec_pgdat(lruvec);
  53. @@ -4743,20 +4746,37 @@ static int evict_pages(struct lruvec *lr
  54. if (list_empty(&list))
  55. return scanned;
  56. -
  57. +retry:
  58. reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false);
  59. + sc->nr_reclaimed += reclaimed;
  60. - list_for_each_entry(page, &list, lru) {
  61. - /* restore LRU_REFS_FLAGS cleared by isolate_page() */
  62. - if (PageWorkingset(page))
  63. - SetPageReferenced(page);
  64. + list_for_each_entry_safe_reverse(page, next, &list, lru) {
  65. + if (!page_evictable(page)) {
  66. + list_del(&page->lru);
  67. + putback_lru_page(page);
  68. + continue;
  69. + }
  70. - /* don't add rejected pages to the oldest generation */
  71. if (PageReclaim(page) &&
  72. - (PageDirty(page) || PageWriteback(page)))
  73. - ClearPageActive(page);
  74. - else
  75. - SetPageActive(page);
  76. + (PageDirty(page) || PageWriteback(page))) {
  77. + /* restore LRU_REFS_FLAGS cleared by isolate_page() */
  78. + if (PageWorkingset(page))
  79. + SetPageReferenced(page);
  80. + continue;
  81. + }
  82. +
  83. + if (skip_retry || PageActive(page) || PageReferenced(page) ||
  84. + page_mapped(page) || PageLocked(page) ||
  85. + PageDirty(page) || PageWriteback(page)) {
  86. + /* don't add rejected pages to the oldest generation */
  87. + set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS,
  88. + BIT(PG_active));
  89. + continue;
  90. + }
  91. +
  92. + /* retry pages that may have missed rotate_reclaimable_page() */
  93. + list_move(&page->lru, &clean);
  94. + sc->nr_scanned -= thp_nr_pages(page);
  95. }
  96. spin_lock_irq(&lruvec->lru_lock);
  97. @@ -4778,7 +4798,13 @@ static int evict_pages(struct lruvec *lr
  98. mem_cgroup_uncharge_list(&list);
  99. free_unref_page_list(&list);
  100. - sc->nr_reclaimed += reclaimed;
  101. + INIT_LIST_HEAD(&list);
  102. + list_splice_init(&clean, &list);
  103. +
  104. + if (!list_empty(&list)) {
  105. + skip_retry = true;
  106. + goto retry;
  107. + }
  108. if (need_swapping && type == LRU_GEN_ANON)
  109. *need_swapping = true;