define page_file_cache() function
authorRik van Riel <riel@redhat.com>
Sun, 19 Oct 2008 03:26:30 +0000 (20:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 20 Oct 2008 15:50:25 +0000 (08:50 -0700)
Define page_file_cache() function to answer the question:
is page backed by a file?

Originally part of Rik van Riel's split-lru patch.  Extracted to make
available for other, independent reclaim patches.

Moved inline function to linux/mm_inline.h where it will be needed by
subsequent "split LRU" and "noreclaim" patches.

Unfortunately this needs to use a page flag, since the PG_swapbacked state
needs to be preserved all the way to the point where the page is last
removed from the LRU.  Trying to derive the status from other info in the
page resulted in wrong VM statistics in earlier split VM patchsets.

The total number of page flags in use on a 32 bit machine after this patch
is 19.

[akpm@linux-foundation.org: fix up out-of-order merge fallout]
[hugh@veritas.com: splitlru: shmem_getpage SetPageSwapBacked sooner[
Signed-off-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>
Signed-off-by: MinChan Kim <minchan.kim@gmail.com>
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/mm_inline.h
include/linux/page-flags.h
mm/memory.c
mm/migrate.c
mm/page_alloc.c
mm/shmem.c
mm/swap_state.c

index 2704729777eff9049c1758914f375ae29a8f582d..96e970485b6c0d4b6a3b80f1df222b51be1bda35 100644 (file)
@@ -1,3 +1,28 @@
+#ifndef LINUX_MM_INLINE_H
+#define LINUX_MM_INLINE_H
+
+/**
+ * page_is_file_cache - should the page be on a file LRU or anon LRU?
+ * @page: the page to test
+ *
+ * Returns !0 if @page is page cache page backed by a regular filesystem,
+ * or 0 if @page is anonymous, tmpfs or otherwise ram or swap backed.
+ * Used by functions that manipulate the LRU lists, to sort a page
+ * onto the right LRU list.
+ *
+ * We would like to get this info without a page flag, but the state
+ * needs to survive until the page is last deleted from the LRU, which
+ * could be as far down as __page_cache_release.
+ */
+static inline int page_is_file_cache(struct page *page)
+{
+       if (PageSwapBacked(page))
+               return 0;
+
+       /* The page is page cache backed by a normal filesystem. */
+       return 1;
+}
+
 static inline void
 add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l)
 {
@@ -65,3 +90,5 @@ static inline enum lru_list page_lru(struct page *page)
 
        return lru;
 }
+
+#endif
index c74d3e87531420faf4e6a65b075ae078ff6277c3..57b688cfb5e2725e2aacf7e3bc5fa5206194c3a2 100644 (file)
@@ -93,6 +93,7 @@ enum pageflags {
        PG_mappedtodisk,        /* Has blocks allocated on-disk */
        PG_reclaim,             /* To be reclaimed asap */
        PG_buddy,               /* Page is free, on buddy lists */
+       PG_swapbacked,          /* Page is backed by RAM/swap */
 #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
        PG_uncached,            /* Page has been mapped as uncached */
 #endif
@@ -176,6 +177,7 @@ PAGEFLAG(SavePinned, savepinned);                   /* Xen */
 PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
 PAGEFLAG(Private, private) __CLEARPAGEFLAG(Private, private)
        __SETPAGEFLAG(Private, private)
+PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
 
 __PAGEFLAG(SlobPage, slob_page)
 __PAGEFLAG(SlobFree, slob_free)
@@ -334,7 +336,8 @@ static inline void __ClearPageTail(struct page *page)
  * Flags checked in bad_page().  Pages on the free list should not have
  * these flags set.  It they are, there is a problem.
  */
-#define PAGE_FLAGS_CLEAR_WHEN_BAD (PAGE_FLAGS | 1 << PG_reclaim | 1 << PG_dirty)
+#define PAGE_FLAGS_CLEAR_WHEN_BAD (PAGE_FLAGS | \
+               1 << PG_reclaim | 1 << PG_dirty | 1 << PG_swapbacked)
 
 /*
  * Flags checked when a page is freed.  Pages being freed should not have
@@ -347,7 +350,8 @@ static inline void __ClearPageTail(struct page *page)
  * Pages being prepped should not have these flags set.  It they are, there
  * is a problem.
  */
-#define PAGE_FLAGS_CHECK_AT_PREP (PAGE_FLAGS | 1 << PG_reserved | 1 << PG_dirty)
+#define PAGE_FLAGS_CHECK_AT_PREP (PAGE_FLAGS | \
+               1 << PG_reserved | 1 << PG_dirty | 1 << PG_swapbacked)
 
 #endif /* !__GENERATING_BOUNDS_H */
 #endif /* PAGE_FLAGS_H */
index 1002f473f497c37f34c5c33d4dfa7d2bd49faed0..7512933dcc105ad8eb2e5ceb75db06d0a6405740 100644 (file)
@@ -1888,6 +1888,7 @@ gotten:
                ptep_clear_flush_notify(vma, address, page_table);
                set_pte_at(mm, address, page_table, entry);
                update_mmu_cache(vma, address, entry);
+               SetPageSwapBacked(new_page);
                lru_cache_add_active(new_page);
                page_add_new_anon_rmap(new_page, vma, address);
 
@@ -2382,6 +2383,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (!pte_none(*page_table))
                goto release;
        inc_mm_counter(mm, anon_rss);
+       SetPageSwapBacked(page);
        lru_cache_add_active(page);
        page_add_new_anon_rmap(page, vma, address);
        set_pte_at(mm, address, page_table, entry);
@@ -2523,6 +2525,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                set_pte_at(mm, address, page_table, entry);
                if (anon) {
                         inc_mm_counter(mm, anon_rss);
+                       SetPageSwapBacked(page);
                         lru_cache_add_active(page);
                         page_add_new_anon_rmap(page, vma, address);
                } else {
index ad15b5ef25997d8176fa48de056ced57c5a23b94..c07327487111375223b4c71283fbbc128cc3e3d7 100644 (file)
@@ -572,6 +572,8 @@ static int move_to_new_page(struct page *newpage, struct page *page)
        /* Prepare mapping for the new page.*/
        newpage->index = page->index;
        newpage->mapping = page->mapping;
+       if (PageSwapBacked(page))
+               SetPageSwapBacked(newpage);
 
        mapping = page_mapping(page);
        if (!mapping)
index ee7a96ef40dc6dfefa59c25e91a49c4df18740d1..2099904d6cc4ded556aad755abd3426044a4ca19 100644 (file)
@@ -462,6 +462,8 @@ static inline int free_pages_check(struct page *page)
                bad_page(page);
        if (PageDirty(page))
                __ClearPageDirty(page);
+       if (PageSwapBacked(page))
+               __ClearPageSwapBacked(page);
        /*
         * For now, we report if PG_reserved was found set, but do not
         * clear it, and do not free the page.  But we shall soon need
index d87958a5f03e95b2cb851722fb91d2c6e5447f66..fd421ed703ed81694af8307c96d48227d13f7414 100644 (file)
@@ -1367,6 +1367,7 @@ repeat:
                                error = -ENOMEM;
                                goto failed;
                        }
+                       SetPageSwapBacked(filepage);
 
                        /* Precharge page while we can wait, compensate after */
                        error = mem_cgroup_cache_charge(filepage, current->mm,
index 797c3831cbec7401ccfecd3ecdc98c7667c8d6bb..7a3ece0b5a3bb9bda19ffc4c695011ba2b8a34d1 100644 (file)
@@ -75,6 +75,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
        BUG_ON(!PageLocked(page));
        BUG_ON(PageSwapCache(page));
        BUG_ON(PagePrivate(page));
+       BUG_ON(!PageSwapBacked(page));
        error = radix_tree_preload(gfp_mask);
        if (!error) {
                page_cache_get(page);
@@ -303,6 +304,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                 * May fail (-ENOMEM) if radix-tree node allocation failed.
                 */
                set_page_locked(new_page);
+               SetPageSwapBacked(new_page);
                err = add_to_swap_cache(new_page, entry, gfp_mask & GFP_KERNEL);
                if (likely(!err)) {
                        /*
@@ -312,6 +314,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                        swap_readpage(NULL, new_page);
                        return new_page;
                }
+               ClearPageSwapBacked(new_page);
                clear_page_locked(new_page);
                swap_free(entry);
        } while (err != -ENOMEM);