]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - mm/vmscan.c
mm: thrash detection-based file cache sizing
[mirror_ubuntu-zesty-kernel.git] / mm / vmscan.c
index 2a0bb8fdb259dcd9d73194d136a59ffa0464d585..1f56a80a7c41442eefa86d7fe82387570cb3bfd0 100644 (file)
@@ -523,7 +523,8 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
  * Same as remove_mapping, but if the page is removed from the mapping, it
  * gets returned with a refcount of 0.
  */
-static int __remove_mapping(struct address_space *mapping, struct page *page)
+static int __remove_mapping(struct address_space *mapping, struct page *page,
+                           bool reclaimed)
 {
        BUG_ON(!PageLocked(page));
        BUG_ON(mapping != page_mapping(page));
@@ -569,10 +570,23 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
                swapcache_free(swap, page);
        } else {
                void (*freepage)(struct page *);
+               void *shadow = NULL;
 
                freepage = mapping->a_ops->freepage;
-
-               __delete_from_page_cache(page, NULL);
+               /*
+                * Remember a shadow entry for reclaimed file cache in
+                * order to detect refaults, thus thrashing, later on.
+                *
+                * But don't store shadows in an address space that is
+                * already exiting.  This is not just an optizimation,
+                * inode reclaim needs to empty out the radix tree or
+                * the nodes are lost.  Don't plant shadows behind its
+                * back.
+                */
+               if (reclaimed && page_is_file_cache(page) &&
+                   !mapping_exiting(mapping))
+                       shadow = workingset_eviction(mapping, page);
+               __delete_from_page_cache(page, shadow);
                spin_unlock_irq(&mapping->tree_lock);
                mem_cgroup_uncharge_cache_page(page);
 
@@ -595,7 +609,7 @@ cannot_free:
  */
 int remove_mapping(struct address_space *mapping, struct page *page)
 {
-       if (__remove_mapping(mapping, page)) {
+       if (__remove_mapping(mapping, page, false)) {
                /*
                 * Unfreezing the refcount with 1 rather than 2 effectively
                 * drops the pagecache ref for us without requiring another
@@ -1065,7 +1079,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        }
                }
 
-               if (!mapping || !__remove_mapping(mapping, page))
+               if (!mapping || !__remove_mapping(mapping, page, true))
                        goto keep_locked;
 
                /*