|
@@ -1449,7 +1449,7 @@ static __always_inline void update_lru_sizes(struct lruvec *lruvec,
|
|
|
*
|
|
|
* Appropriate locks must be held before calling this function.
|
|
|
*
|
|
|
- * @nr_to_scan: The number of pages to look through on the list.
|
|
|
+ * @nr_to_scan: The number of eligible pages to look through on the list.
|
|
|
* @lruvec: The LRU vector to pull pages from.
|
|
|
* @dst: The temp list to put pages on to.
|
|
|
* @nr_scanned: The number of pages that were scanned.
|
|
@@ -1469,11 +1469,13 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
|
|
|
unsigned long nr_zone_taken[MAX_NR_ZONES] = { 0 };
|
|
|
unsigned long nr_skipped[MAX_NR_ZONES] = { 0, };
|
|
|
unsigned long skipped = 0;
|
|
|
- unsigned long scan, nr_pages;
|
|
|
+ unsigned long scan, total_scan, nr_pages;
|
|
|
LIST_HEAD(pages_skipped);
|
|
|
|
|
|
- for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan &&
|
|
|
- !list_empty(src); scan++) {
|
|
|
+ scan = 0;
|
|
|
+ for (total_scan = 0;
|
|
|
+ scan < nr_to_scan && nr_taken < nr_to_scan && !list_empty(src);
|
|
|
+ total_scan++) {
|
|
|
struct page *page;
|
|
|
|
|
|
page = lru_to_page(src);
|
|
@@ -1487,6 +1489,13 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Do not count skipped pages because that makes the function
|
|
|
+ * return with no isolated pages if the LRU mostly contains
|
|
|
+ * ineligible pages. This causes the VM to not reclaim any
|
|
|
+ * pages, triggering a premature OOM.
|
|
|
+ */
|
|
|
+ scan++;
|
|
|
switch (__isolate_lru_page(page, mode)) {
|
|
|
case 0:
|
|
|
nr_pages = hpage_nr_pages(page);
|
|
@@ -1524,9 +1533,9 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
|
|
|
skipped += nr_skipped[zid];
|
|
|
}
|
|
|
}
|
|
|
- *nr_scanned = scan;
|
|
|
+ *nr_scanned = total_scan;
|
|
|
trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan,
|
|
|
- scan, skipped, nr_taken, mode, lru);
|
|
|
+ total_scan, skipped, nr_taken, mode, lru);
|
|
|
update_lru_sizes(lruvec, lru, nr_zone_taken);
|
|
|
return nr_taken;
|
|
|
}
|