mm/workingset: Convert workingset_eviction() to take a folio

This removes an assumption that THPs are the only kind of compound
pages and removes a few hidden calls to compound_head().
Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 1b7f7e58
...@@ -328,7 +328,7 @@ static inline swp_entry_t folio_swap_entry(struct folio *folio) ...@@ -328,7 +328,7 @@ static inline swp_entry_t folio_swap_entry(struct folio *folio)
/* linux/mm/workingset.c */ /* linux/mm/workingset.c */
void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages); void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages);
void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg); void *workingset_eviction(struct folio *folio, struct mem_cgroup *target_memcg);
void workingset_refault(struct folio *folio, void *shadow); void workingset_refault(struct folio *folio, void *shadow);
void workingset_activation(struct folio *folio); void workingset_activation(struct folio *folio);
......
...@@ -1242,6 +1242,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping) ...@@ -1242,6 +1242,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping)
static int __remove_mapping(struct address_space *mapping, struct page *page, static int __remove_mapping(struct address_space *mapping, struct page *page,
bool reclaimed, struct mem_cgroup *target_memcg) bool reclaimed, struct mem_cgroup *target_memcg)
{ {
struct folio *folio = page_folio(page);
int refcount; int refcount;
void *shadow = NULL; void *shadow = NULL;
...@@ -1289,7 +1290,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, ...@@ -1289,7 +1290,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
swp_entry_t swap = { .val = page_private(page) }; swp_entry_t swap = { .val = page_private(page) };
mem_cgroup_swapout(page, swap); mem_cgroup_swapout(page, swap);
if (reclaimed && !mapping_exiting(mapping)) if (reclaimed && !mapping_exiting(mapping))
shadow = workingset_eviction(page, target_memcg); shadow = workingset_eviction(folio, target_memcg);
__delete_from_swap_cache(page, swap, shadow); __delete_from_swap_cache(page, swap, shadow);
xa_unlock_irq(&mapping->i_pages); xa_unlock_irq(&mapping->i_pages);
put_swap_page(page, swap); put_swap_page(page, swap);
...@@ -1315,8 +1316,8 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, ...@@ -1315,8 +1316,8 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
*/ */
if (reclaimed && page_is_file_lru(page) && if (reclaimed && page_is_file_lru(page) &&
!mapping_exiting(mapping) && !dax_mapping(mapping)) !mapping_exiting(mapping) && !dax_mapping(mapping))
shadow = workingset_eviction(page, target_memcg); shadow = workingset_eviction(folio, target_memcg);
__delete_from_page_cache(page, shadow); __filemap_remove_folio(folio, shadow);
xa_unlock_irq(&mapping->i_pages); xa_unlock_irq(&mapping->i_pages);
if (mapping_shrinkable(mapping)) if (mapping_shrinkable(mapping))
inode_add_lru(mapping->host); inode_add_lru(mapping->host);
......
...@@ -245,31 +245,32 @@ void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages) ...@@ -245,31 +245,32 @@ void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages)
} }
/** /**
* workingset_eviction - note the eviction of a page from memory * workingset_eviction - note the eviction of a folio from memory
* @target_memcg: the cgroup that is causing the reclaim * @target_memcg: the cgroup that is causing the reclaim
* @page: the page being evicted * @folio: the folio being evicted
* *
* Return: a shadow entry to be stored in @page->mapping->i_pages in place * Return: a shadow entry to be stored in @folio->mapping->i_pages in place
* of the evicted @page so that a later refault can be detected. * of the evicted @folio so that a later refault can be detected.
*/ */
void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg) void *workingset_eviction(struct folio *folio, struct mem_cgroup *target_memcg)
{ {
struct pglist_data *pgdat = page_pgdat(page); struct pglist_data *pgdat = folio_pgdat(folio);
unsigned long eviction; unsigned long eviction;
struct lruvec *lruvec; struct lruvec *lruvec;
int memcgid; int memcgid;
/* Page is fully exclusive and pins page's memory cgroup pointer */ /* Folio is fully exclusive and pins folio's memory cgroup pointer */
VM_BUG_ON_PAGE(PageLRU(page), page); VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
VM_BUG_ON_PAGE(page_count(page), page); VM_BUG_ON_FOLIO(folio_ref_count(folio), folio);
VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
lruvec = mem_cgroup_lruvec(target_memcg, pgdat); lruvec = mem_cgroup_lruvec(target_memcg, pgdat);
/* XXX: target_memcg can be NULL, go through lruvec */ /* XXX: target_memcg can be NULL, go through lruvec */
memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); memcgid = mem_cgroup_id(lruvec_memcg(lruvec));
eviction = atomic_long_read(&lruvec->nonresident_age); eviction = atomic_long_read(&lruvec->nonresident_age);
workingset_age_nonresident(lruvec, thp_nr_pages(page)); workingset_age_nonresident(lruvec, folio_nr_pages(folio));
return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); return pack_shadow(memcgid, pgdat, eviction,
folio_test_workingset(folio));
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment