|
@@ -1284,32 +1284,6 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
|
|
return nr_taken;
|
|
return nr_taken;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * clear_active_flags() is a helper for shrink_active_list(), clearing
|
|
|
|
- * any active bits from the pages in the list.
|
|
|
|
- */
|
|
|
|
-static unsigned long clear_active_flags(struct list_head *page_list,
|
|
|
|
- unsigned int *count)
|
|
|
|
-{
|
|
|
|
- int nr_active = 0;
|
|
|
|
- int lru;
|
|
|
|
- struct page *page;
|
|
|
|
-
|
|
|
|
- list_for_each_entry(page, page_list, lru) {
|
|
|
|
- int numpages = hpage_nr_pages(page);
|
|
|
|
- lru = page_lru_base_type(page);
|
|
|
|
- if (PageActive(page)) {
|
|
|
|
- lru += LRU_ACTIVE;
|
|
|
|
- ClearPageActive(page);
|
|
|
|
- nr_active += numpages;
|
|
|
|
- }
|
|
|
|
- if (count)
|
|
|
|
- count[lru] += numpages;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return nr_active;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* isolate_lru_page - tries to isolate a page from its LRU list
|
|
* isolate_lru_page - tries to isolate a page from its LRU list
|
|
* @page: page to isolate from its LRU list
|
|
* @page: page to isolate from its LRU list
|
|
@@ -1383,26 +1357,21 @@ static int too_many_isolated(struct zone *zone, int file,
|
|
return isolated > inactive;
|
|
return isolated > inactive;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * TODO: Try merging with migrations version of putback_lru_pages
|
|
|
|
- */
|
|
|
|
static noinline_for_stack void
|
|
static noinline_for_stack void
|
|
-putback_lru_pages(struct mem_cgroup_zone *mz, struct scan_control *sc,
|
|
|
|
- unsigned long nr_anon, unsigned long nr_file,
|
|
|
|
- struct list_head *page_list)
|
|
|
|
|
|
+putback_inactive_pages(struct mem_cgroup_zone *mz,
|
|
|
|
+ struct list_head *page_list)
|
|
{
|
|
{
|
|
- struct page *page;
|
|
|
|
- LIST_HEAD(pages_to_free);
|
|
|
|
- struct zone *zone = mz->zone;
|
|
|
|
struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
|
|
struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
|
|
|
|
+ struct zone *zone = mz->zone;
|
|
|
|
+ LIST_HEAD(pages_to_free);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Put back any unfreeable pages.
|
|
* Put back any unfreeable pages.
|
|
*/
|
|
*/
|
|
- spin_lock(&zone->lru_lock);
|
|
|
|
while (!list_empty(page_list)) {
|
|
while (!list_empty(page_list)) {
|
|
|
|
+ struct page *page = lru_to_page(page_list);
|
|
int lru;
|
|
int lru;
|
|
- page = lru_to_page(page_list);
|
|
|
|
|
|
+
|
|
VM_BUG_ON(PageLRU(page));
|
|
VM_BUG_ON(PageLRU(page));
|
|
list_del(&page->lru);
|
|
list_del(&page->lru);
|
|
if (unlikely(!page_evictable(page, NULL))) {
|
|
if (unlikely(!page_evictable(page, NULL))) {
|
|
@@ -1432,26 +1401,40 @@ putback_lru_pages(struct mem_cgroup_zone *mz, struct scan_control *sc,
|
|
list_add(&page->lru, &pages_to_free);
|
|
list_add(&page->lru, &pages_to_free);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
|
|
|
|
- __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
|
|
|
|
|
|
|
|
- spin_unlock_irq(&zone->lru_lock);
|
|
|
|
- free_hot_cold_page_list(&pages_to_free, 1);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * To save our caller's stack, now use input list for pages to free.
|
|
|
|
+ */
|
|
|
|
+ list_splice(&pages_to_free, page_list);
|
|
}
|
|
}
|
|
|
|
|
|
static noinline_for_stack void
|
|
static noinline_for_stack void
|
|
update_isolated_counts(struct mem_cgroup_zone *mz,
|
|
update_isolated_counts(struct mem_cgroup_zone *mz,
|
|
- struct scan_control *sc,
|
|
|
|
|
|
+ struct list_head *page_list,
|
|
unsigned long *nr_anon,
|
|
unsigned long *nr_anon,
|
|
- unsigned long *nr_file,
|
|
|
|
- struct list_head *isolated_list)
|
|
|
|
|
|
+ unsigned long *nr_file)
|
|
{
|
|
{
|
|
- unsigned long nr_active;
|
|
|
|
|
|
+ struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
|
|
struct zone *zone = mz->zone;
|
|
struct zone *zone = mz->zone;
|
|
unsigned int count[NR_LRU_LISTS] = { 0, };
|
|
unsigned int count[NR_LRU_LISTS] = { 0, };
|
|
- struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
|
|
|
|
|
|
+ unsigned long nr_active = 0;
|
|
|
|
+ struct page *page;
|
|
|
|
+ int lru;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Count pages and clear active flags
|
|
|
|
+ */
|
|
|
|
+ list_for_each_entry(page, page_list, lru) {
|
|
|
|
+ int numpages = hpage_nr_pages(page);
|
|
|
|
+ lru = page_lru_base_type(page);
|
|
|
|
+ if (PageActive(page)) {
|
|
|
|
+ lru += LRU_ACTIVE;
|
|
|
|
+ ClearPageActive(page);
|
|
|
|
+ nr_active += numpages;
|
|
|
|
+ }
|
|
|
|
+ count[lru] += numpages;
|
|
|
|
+ }
|
|
|
|
|
|
- nr_active = clear_active_flags(isolated_list, count);
|
|
|
|
__count_vm_events(PGDEACTIVATE, nr_active);
|
|
__count_vm_events(PGDEACTIVATE, nr_active);
|
|
|
|
|
|
__mod_zone_page_state(zone, NR_ACTIVE_FILE,
|
|
__mod_zone_page_state(zone, NR_ACTIVE_FILE,
|
|
@@ -1465,8 +1448,6 @@ update_isolated_counts(struct mem_cgroup_zone *mz,
|
|
|
|
|
|
*nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
|
|
*nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
|
|
*nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
|
|
*nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
|
|
- __mod_zone_page_state(zone, NR_ISOLATED_ANON, *nr_anon);
|
|
|
|
- __mod_zone_page_state(zone, NR_ISOLATED_FILE, *nr_file);
|
|
|
|
|
|
|
|
reclaim_stat->recent_scanned[0] += *nr_anon;
|
|
reclaim_stat->recent_scanned[0] += *nr_anon;
|
|
reclaim_stat->recent_scanned[1] += *nr_file;
|
|
reclaim_stat->recent_scanned[1] += *nr_file;
|
|
@@ -1571,7 +1552,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct mem_cgroup_zone *mz,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- update_isolated_counts(mz, sc, &nr_anon, &nr_file, &page_list);
|
|
|
|
|
|
+ update_isolated_counts(mz, &page_list, &nr_anon, &nr_file);
|
|
|
|
+
|
|
|
|
+ __mod_zone_page_state(zone, NR_ISOLATED_ANON, nr_anon);
|
|
|
|
+ __mod_zone_page_state(zone, NR_ISOLATED_FILE, nr_file);
|
|
|
|
|
|
spin_unlock_irq(&zone->lru_lock);
|
|
spin_unlock_irq(&zone->lru_lock);
|
|
|
|
|
|
@@ -1585,12 +1569,20 @@ shrink_inactive_list(unsigned long nr_to_scan, struct mem_cgroup_zone *mz,
|
|
priority, &nr_dirty, &nr_writeback);
|
|
priority, &nr_dirty, &nr_writeback);
|
|
}
|
|
}
|
|
|
|
|
|
- local_irq_disable();
|
|
|
|
|
|
+ spin_lock_irq(&zone->lru_lock);
|
|
|
|
+
|
|
if (current_is_kswapd())
|
|
if (current_is_kswapd())
|
|
__count_vm_events(KSWAPD_STEAL, nr_reclaimed);
|
|
__count_vm_events(KSWAPD_STEAL, nr_reclaimed);
|
|
__count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
|
|
__count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
|
|
|
|
|
|
- putback_lru_pages(mz, sc, nr_anon, nr_file, &page_list);
|
|
|
|
|
|
+ putback_inactive_pages(mz, &page_list);
|
|
|
|
+
|
|
|
|
+ __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
|
|
|
|
+ __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
|
|
|
|
+
|
|
|
|
+ spin_unlock_irq(&zone->lru_lock);
|
|
|
|
+
|
|
|
|
+ free_hot_cold_page_list(&page_list, 1);
|
|
|
|
|
|
/*
|
|
/*
|
|
* If reclaim is isolating dirty pages under writeback, it implies
|
|
* If reclaim is isolating dirty pages under writeback, it implies
|