diff options
author | Jérôme Glisse <jglisse@redhat.com> | 2018-09-28 13:59:22 -0400 |
---|---|---|
committer | Jérôme Glisse <jglisse@redhat.com> | 2018-09-28 13:59:22 -0400 |
commit | a5dbc0fe7e71d347067579f13579df372ec48389 (patch) | |
tree | cf5e66b84e85d21de9471dbf88bd4365a1a917b1 | |
parent | ae596de1a0c8c2c924dc99d23c026259372ab234 (diff) |
mm/vmscan: do not try to reclaim page pinned by a GUP (get_user_page)
Page pinned by a get user as we won't be able to free them. This avoids
doing all the heavy work: scanning page mapping reference status, trying
to unmap the page, write it to disk (if file back and dirty or swap),
trying to release page (if file back) ...
Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
-rw-r--r-- | mm/vmscan.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 7e7d25504651..a4e4a4725afc 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -4138,15 +4138,32 @@ int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) * Reasons page might not be evictable: * (1) page's mapping marked unevictable * (2) page is part of an mlocked VMA - * + * (3) page is pinned by some GUP (get_user_pages()) */ int page_evictable(struct page *page) { - int ret; + struct address_space *mapping = page_mapping(page); + int ret, extra; + + /* + * If page has a mapping then it has an extra refcount and can another + * extra one if it has its private fields set. + */ + extra = mapping ? 1 + page_has_private(page) : 0; + /* If page is isolated from lru then it has an extra refcount. */ + extra += PageLRU(page) ? 0 : 1; + /* + * GUP (get_user_pages()) will increment the refcount on the page so at + * this point if the refcount is bigger than mapcount it means that the + * page is pinned by some GUP and it is pointless to try to reclaim any + * such page. Ignore any extra reference that are not from a GUP. + */ + if ((page_count(page) - extra) > page_mapcount(page)) + return 0; /* Prevent address_space of inode and swap cache from being freed */ rcu_read_lock(); - ret = !mapping_unevictable(page_mapping(page)) && !PageMlocked(page); + ret = !mapping_unevictable(mapping) && !PageMlocked(page); rcu_read_unlock(); return ret; } |