diff for duplicates of <20160505150907.GF28755@redhat.com> diff --git a/a/1.txt b/N1/1.txt index bc06c76..d9b1293 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -14,3 +14,262 @@ results in less code at the very least but then we've to check "total_mapcount == 1" instead of just a true/false "local_rmap" (which might have been more self explanatory) if reuse_swap_page returns true. + +>From 4158c4b38883fb3481d70f6a4eebbbf2b379a791 Mon Sep 17 00:00:00 2001 +From: Andrea Arcangeli <aarcange@redhat.com> +Date: Fri, 29 Apr 2016 01:05:06 +0200 +Subject: [PATCH 1/1] mm: thp: calculate the mapcount correctly for THP pages + during WP faults + +This will provide fully accuracy to the mapcount calculation in the +write protect faults, so page pinning will not get broken by false +positive copy-on-writes. + +total_mapcount() isn't the right calculation needed in +reuse_swap_page(), so this introduces a page_trans_huge_mapcount() +that is effectively the full accurate return value for page_mapcount() +if dealing with Transparent Hugepages, however we only use the +page_trans_huge_mapcount() during COW faults where it strictly needed, +due to its higher runtime cost. + +This also provide at practical zero cost the total_mapcount +information which is needed to know if we can still relocate the page +anon_vma to the local vma. If page_trans_huge_mapcount() returns 1 we +can reuse the page no matter if it's a pte or a pmd_trans_huge +triggering the fault, but we can only relocate the page anon_vma to +the local vma->anon_vma if we're sure it's only this "vma" mapping the +whole THP physical range. + +Kirill A. Shutemov reported the problem with moving the page anon_vma +to the local vma->anon_vma in a previous version of this patch. + +Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> +--- + include/linux/mm.h | 9 +++++++ + include/linux/swap.h | 8 ++++--- + mm/huge_memory.c | 68 +++++++++++++++++++++++++++++++++++++++++++++------- + mm/memory.c | 21 +++++++++------- + mm/swapfile.c | 13 +++++----- + 5 files changed, 93 insertions(+), 26 deletions(-) + +diff --git a/include/linux/mm.h b/include/linux/mm.h +index a55e5be..263f229 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -500,11 +500,20 @@ static inline int page_mapcount(struct page *page) + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + int total_mapcount(struct page *page); ++int page_trans_huge_mapcount(struct page *page, int *total_mapcount); + #else + static inline int total_mapcount(struct page *page) + { + return page_mapcount(page); + } ++static inline int page_trans_huge_mapcount(struct page *page, ++ int *total_mapcount) ++{ ++ int mapcount = page_mapcount(page); ++ if (total_mapcount) ++ *total_mapcount = mapcount; ++ return mapcount; ++} + #endif + + static inline struct page *virt_to_head_page(const void *x) +diff --git a/include/linux/swap.h b/include/linux/swap.h +index 2b83359..acef20d 100644 +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -418,7 +418,7 @@ extern sector_t swapdev_block(int, pgoff_t); + extern int page_swapcount(struct page *); + extern int swp_swapcount(swp_entry_t entry); + extern struct swap_info_struct *page_swap_info(struct page *); +-extern int reuse_swap_page(struct page *); ++extern bool reuse_swap_page(struct page *, int *); + extern int try_to_free_swap(struct page *); + struct backing_dev_info; + +@@ -513,8 +513,10 @@ static inline int swp_swapcount(swp_entry_t entry) + return 0; + } + +-#define reuse_swap_page(page) \ +- (!PageTransCompound(page) && page_mapcount(page) == 1) ++static inline bool reuse_swap_page(struct page *page, int *total_mapcount) ++{ ++ return page_trans_huge_mapcount(page, total_mapcount) == 1; ++} + + static inline int try_to_free_swap(struct page *page) + { +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index 86f9f8b..d4d61f5 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -1298,15 +1298,9 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, + VM_BUG_ON_PAGE(!PageCompound(page) || !PageHead(page), page); + /* + * We can only reuse the page if nobody else maps the huge page or it's +- * part. We can do it by checking page_mapcount() on each sub-page, but +- * it's expensive. +- * The cheaper way is to check page_count() to be equal 1: every +- * mapcount takes page reference reference, so this way we can +- * guarantee, that the PMD is the only mapping. +- * This can give false negative if somebody pinned the page, but that's +- * fine. ++ * part. + */ +- if (page_mapcount(page) == 1 && page_count(page) == 1) { ++ if (page_trans_huge_mapcount(page, NULL) == 1) { + pmd_t entry; + entry = pmd_mkyoung(orig_pmd); + entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma); +@@ -2080,7 +2074,8 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma, + if (pte_write(pteval)) { + writable = true; + } else { +- if (PageSwapCache(page) && !reuse_swap_page(page)) { ++ if (PageSwapCache(page) && ++ !reuse_swap_page(page, NULL)) { + unlock_page(page); + result = SCAN_SWAP_CACHE_PAGE; + goto out; +@@ -3225,6 +3220,61 @@ int total_mapcount(struct page *page) + } + + /* ++ * This calculates accurately how many mappings a transparent hugepage ++ * has (unlike page_mapcount() which isn't fully accurate). This full ++ * accuracy is primarily needed to know if copy-on-write faults can ++ * takeover the page and change the mapping to read-write instead of ++ * copying them. At the same time this returns the total_mapcount too. ++ * ++ * The return value is telling if the page can be reused as it returns ++ * the highest mapcount any one of the subpages has. If the return ++ * value is one, even if different processes are mapping different ++ * subpages of the transparent hugepage, they can all reuse it, ++ * because each process is reusing a different subpage. ++ * ++ * The total_mapcount is instead counting all virtual mappings of the ++ * subpages. If the total_mapcount is equal to "one", it tells the ++ * caller all mappings belong to the same "mm" and in turn the ++ * anon_vma of the transparent hugepage can become the vma->anon_vma ++ * local one as no other process may be mapping any of the subpages. ++ * ++ * It would be more accurate to replace page_mapcount() with ++ * page_trans_huge_mapcount(), however we only use ++ * page_trans_huge_mapcount() in the copy-on-write faults where we ++ * need full accuracy to avoid breaking page pinning, because ++ * page_trans_huge_mapcount is slower than page_mapcount(). ++ */ ++int page_trans_huge_mapcount(struct page *page, int *total_mapcount) ++{ ++ int i, ret, _total_mapcount, mapcount; ++ ++ /* hugetlbfs shouldn't call it */ ++ VM_BUG_ON_PAGE(PageHuge(page), page); ++ ++ if (likely(!PageTransCompound(page))) ++ return atomic_read(&page->_mapcount) + 1; ++ ++ page = compound_head(page); ++ ++ _total_mapcount = ret = 0; ++ for (i = 0; i < HPAGE_PMD_NR; i++) { ++ mapcount = atomic_read(&page[i]._mapcount) + 1; ++ ret = max(ret, mapcount); ++ _total_mapcount += mapcount; ++ } ++ if (PageDoubleMap(page)) { ++ ret -= 1; ++ _total_mapcount -= HPAGE_PMD_NR; ++ } ++ mapcount = compound_mapcount(page); ++ ret += mapcount; ++ _total_mapcount += mapcount; ++ if (total_mapcount) ++ *total_mapcount = _total_mapcount; ++ return ret; ++} ++ ++/* + * This function splits huge page into normal pages. @page can point to any + * subpage of huge page to split. Split doesn't change the position of @page. + * +diff --git a/mm/memory.c b/mm/memory.c +index 93897f2..1589aa4 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2340,6 +2340,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, + * not dirty accountable. + */ + if (PageAnon(old_page) && !PageKsm(old_page)) { ++ int total_mapcount; + if (!trylock_page(old_page)) { + get_page(old_page); + pte_unmap_unlock(page_table, ptl); +@@ -2354,13 +2355,17 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, + } + put_page(old_page); + } +- if (reuse_swap_page(old_page)) { +- /* +- * The page is all ours. Move it to our anon_vma so +- * the rmap code will not search our parent or siblings. +- * Protected against the rmap code by the page lock. +- */ +- page_move_anon_rmap(old_page, vma, address); ++ if (reuse_swap_page(old_page, &total_mapcount)) { ++ if (total_mapcount == 1) { ++ /* ++ * The page is all ours. Move it to ++ * our anon_vma so the rmap code will ++ * not search our parent or siblings. ++ * Protected against the rmap code by ++ * the page lock. ++ */ ++ page_move_anon_rmap(old_page, vma, address); ++ } + unlock_page(old_page); + return wp_page_reuse(mm, vma, address, page_table, ptl, + orig_pte, old_page, 0, 0); +@@ -2584,7 +2589,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, + inc_mm_counter_fast(mm, MM_ANONPAGES); + dec_mm_counter_fast(mm, MM_SWAPENTS); + pte = mk_pte(page, vma->vm_page_prot); +- if ((flags & FAULT_FLAG_WRITE) && reuse_swap_page(page)) { ++ if ((flags & FAULT_FLAG_WRITE) && reuse_swap_page(page, NULL)) { + pte = maybe_mkwrite(pte_mkdirty(pte), vma); + flags &= ~FAULT_FLAG_WRITE; + ret |= VM_FAULT_WRITE; +diff --git a/mm/swapfile.c b/mm/swapfile.c +index 83874ec..031713ab 100644 +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -922,18 +922,19 @@ out: + * to it. And as a side-effect, free up its swap: because the old content + * on disk will never be read, and seeking back there to write new content + * later would only waste time away from clustering. ++ * ++ * NOTE: total_mapcount should not be relied upon by the caller if ++ * reuse_swap_page() returns false, but it may be always overwritten ++ * (see the other implementation for CONFIG_SWAP=n). + */ +-int reuse_swap_page(struct page *page) ++bool reuse_swap_page(struct page *page, int *total_mapcount) + { + int count; + + VM_BUG_ON_PAGE(!PageLocked(page), page); + if (unlikely(PageKsm(page))) +- return 0; +- /* The page is part of THP and cannot be reused */ +- if (PageTransCompound(page)) +- return 0; +- count = page_mapcount(page); ++ return false; ++ count = page_trans_huge_mapcount(page, total_mapcount); + if (count <= 1 && PageSwapCache(page)) { + count += page_swapcount(page); + if (count == 1 && !PageWriteback(page)) { diff --git a/a/content_digest b/N1/content_digest index 01fd966..d8a3038 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -33,6 +33,265 @@ "results in less code at the very least but then we've to check\n" "\"total_mapcount == 1\" instead of just a true/false \"local_rmap\" (which\n" "might have been more self explanatory) if reuse_swap_page returns\n" - true. + "true.\n" + "\n" + ">From 4158c4b38883fb3481d70f6a4eebbbf2b379a791 Mon Sep 17 00:00:00 2001\n" + "From: Andrea Arcangeli <aarcange@redhat.com>\n" + "Date: Fri, 29 Apr 2016 01:05:06 +0200\n" + "Subject: [PATCH 1/1] mm: thp: calculate the mapcount correctly for THP pages\n" + " during WP faults\n" + "\n" + "This will provide fully accuracy to the mapcount calculation in the\n" + "write protect faults, so page pinning will not get broken by false\n" + "positive copy-on-writes.\n" + "\n" + "total_mapcount() isn't the right calculation needed in\n" + "reuse_swap_page(), so this introduces a page_trans_huge_mapcount()\n" + "that is effectively the full accurate return value for page_mapcount()\n" + "if dealing with Transparent Hugepages, however we only use the\n" + "page_trans_huge_mapcount() during COW faults where it strictly needed,\n" + "due to its higher runtime cost.\n" + "\n" + "This also provide at practical zero cost the total_mapcount\n" + "information which is needed to know if we can still relocate the page\n" + "anon_vma to the local vma. If page_trans_huge_mapcount() returns 1 we\n" + "can reuse the page no matter if it's a pte or a pmd_trans_huge\n" + "triggering the fault, but we can only relocate the page anon_vma to\n" + "the local vma->anon_vma if we're sure it's only this \"vma\" mapping the\n" + "whole THP physical range.\n" + "\n" + "Kirill A. Shutemov reported the problem with moving the page anon_vma\n" + "to the local vma->anon_vma in a previous version of this patch.\n" + "\n" + "Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>\n" + "---\n" + " include/linux/mm.h | 9 +++++++\n" + " include/linux/swap.h | 8 ++++---\n" + " mm/huge_memory.c | 68 +++++++++++++++++++++++++++++++++++++++++++++-------\n" + " mm/memory.c | 21 +++++++++-------\n" + " mm/swapfile.c | 13 +++++-----\n" + " 5 files changed, 93 insertions(+), 26 deletions(-)\n" + "\n" + "diff --git a/include/linux/mm.h b/include/linux/mm.h\n" + "index a55e5be..263f229 100644\n" + "--- a/include/linux/mm.h\n" + "+++ b/include/linux/mm.h\n" + "@@ -500,11 +500,20 @@ static inline int page_mapcount(struct page *page)\n" + " \n" + " #ifdef CONFIG_TRANSPARENT_HUGEPAGE\n" + " int total_mapcount(struct page *page);\n" + "+int page_trans_huge_mapcount(struct page *page, int *total_mapcount);\n" + " #else\n" + " static inline int total_mapcount(struct page *page)\n" + " {\n" + " \treturn page_mapcount(page);\n" + " }\n" + "+static inline int page_trans_huge_mapcount(struct page *page,\n" + "+\t\t\t\t\t int *total_mapcount)\n" + "+{\n" + "+\tint mapcount = page_mapcount(page);\n" + "+\tif (total_mapcount)\n" + "+\t\t*total_mapcount = mapcount;\n" + "+\treturn mapcount;\n" + "+}\n" + " #endif\n" + " \n" + " static inline struct page *virt_to_head_page(const void *x)\n" + "diff --git a/include/linux/swap.h b/include/linux/swap.h\n" + "index 2b83359..acef20d 100644\n" + "--- a/include/linux/swap.h\n" + "+++ b/include/linux/swap.h\n" + "@@ -418,7 +418,7 @@ extern sector_t swapdev_block(int, pgoff_t);\n" + " extern int page_swapcount(struct page *);\n" + " extern int swp_swapcount(swp_entry_t entry);\n" + " extern struct swap_info_struct *page_swap_info(struct page *);\n" + "-extern int reuse_swap_page(struct page *);\n" + "+extern bool reuse_swap_page(struct page *, int *);\n" + " extern int try_to_free_swap(struct page *);\n" + " struct backing_dev_info;\n" + " \n" + "@@ -513,8 +513,10 @@ static inline int swp_swapcount(swp_entry_t entry)\n" + " \treturn 0;\n" + " }\n" + " \n" + "-#define reuse_swap_page(page) \\\n" + "-\t(!PageTransCompound(page) && page_mapcount(page) == 1)\n" + "+static inline bool reuse_swap_page(struct page *page, int *total_mapcount)\n" + "+{\n" + "+\treturn page_trans_huge_mapcount(page, total_mapcount) == 1;\n" + "+}\n" + " \n" + " static inline int try_to_free_swap(struct page *page)\n" + " {\n" + "diff --git a/mm/huge_memory.c b/mm/huge_memory.c\n" + "index 86f9f8b..d4d61f5 100644\n" + "--- a/mm/huge_memory.c\n" + "+++ b/mm/huge_memory.c\n" + "@@ -1298,15 +1298,9 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,\n" + " \tVM_BUG_ON_PAGE(!PageCompound(page) || !PageHead(page), page);\n" + " \t/*\n" + " \t * We can only reuse the page if nobody else maps the huge page or it's\n" + "-\t * part. We can do it by checking page_mapcount() on each sub-page, but\n" + "-\t * it's expensive.\n" + "-\t * The cheaper way is to check page_count() to be equal 1: every\n" + "-\t * mapcount takes page reference reference, so this way we can\n" + "-\t * guarantee, that the PMD is the only mapping.\n" + "-\t * This can give false negative if somebody pinned the page, but that's\n" + "-\t * fine.\n" + "+\t * part.\n" + " \t */\n" + "-\tif (page_mapcount(page) == 1 && page_count(page) == 1) {\n" + "+\tif (page_trans_huge_mapcount(page, NULL) == 1) {\n" + " \t\tpmd_t entry;\n" + " \t\tentry = pmd_mkyoung(orig_pmd);\n" + " \t\tentry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);\n" + "@@ -2080,7 +2074,8 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,\n" + " \t\tif (pte_write(pteval)) {\n" + " \t\t\twritable = true;\n" + " \t\t} else {\n" + "-\t\t\tif (PageSwapCache(page) && !reuse_swap_page(page)) {\n" + "+\t\t\tif (PageSwapCache(page) &&\n" + "+\t\t\t !reuse_swap_page(page, NULL)) {\n" + " \t\t\t\tunlock_page(page);\n" + " \t\t\t\tresult = SCAN_SWAP_CACHE_PAGE;\n" + " \t\t\t\tgoto out;\n" + "@@ -3225,6 +3220,61 @@ int total_mapcount(struct page *page)\n" + " }\n" + " \n" + " /*\n" + "+ * This calculates accurately how many mappings a transparent hugepage\n" + "+ * has (unlike page_mapcount() which isn't fully accurate). This full\n" + "+ * accuracy is primarily needed to know if copy-on-write faults can\n" + "+ * takeover the page and change the mapping to read-write instead of\n" + "+ * copying them. At the same time this returns the total_mapcount too.\n" + "+ *\n" + "+ * The return value is telling if the page can be reused as it returns\n" + "+ * the highest mapcount any one of the subpages has. If the return\n" + "+ * value is one, even if different processes are mapping different\n" + "+ * subpages of the transparent hugepage, they can all reuse it,\n" + "+ * because each process is reusing a different subpage.\n" + "+ *\n" + "+ * The total_mapcount is instead counting all virtual mappings of the\n" + "+ * subpages. If the total_mapcount is equal to \"one\", it tells the\n" + "+ * caller all mappings belong to the same \"mm\" and in turn the\n" + "+ * anon_vma of the transparent hugepage can become the vma->anon_vma\n" + "+ * local one as no other process may be mapping any of the subpages.\n" + "+ *\n" + "+ * It would be more accurate to replace page_mapcount() with\n" + "+ * page_trans_huge_mapcount(), however we only use\n" + "+ * page_trans_huge_mapcount() in the copy-on-write faults where we\n" + "+ * need full accuracy to avoid breaking page pinning, because\n" + "+ * page_trans_huge_mapcount is slower than page_mapcount().\n" + "+ */\n" + "+int page_trans_huge_mapcount(struct page *page, int *total_mapcount)\n" + "+{\n" + "+\tint i, ret, _total_mapcount, mapcount;\n" + "+\n" + "+\t/* hugetlbfs shouldn't call it */\n" + "+\tVM_BUG_ON_PAGE(PageHuge(page), page);\n" + "+\n" + "+\tif (likely(!PageTransCompound(page)))\n" + "+\t\treturn atomic_read(&page->_mapcount) + 1;\n" + "+\n" + "+\tpage = compound_head(page);\n" + "+\n" + "+\t_total_mapcount = ret = 0;\n" + "+\tfor (i = 0; i < HPAGE_PMD_NR; i++) {\n" + "+\t\tmapcount = atomic_read(&page[i]._mapcount) + 1;\n" + "+\t\tret = max(ret, mapcount);\n" + "+\t\t_total_mapcount += mapcount;\n" + "+\t}\n" + "+\tif (PageDoubleMap(page)) {\n" + "+\t\tret -= 1;\n" + "+\t\t_total_mapcount -= HPAGE_PMD_NR;\n" + "+\t}\n" + "+\tmapcount = compound_mapcount(page);\n" + "+\tret += mapcount;\n" + "+\t_total_mapcount += mapcount;\n" + "+\tif (total_mapcount)\n" + "+\t\t*total_mapcount = _total_mapcount;\n" + "+\treturn ret;\n" + "+}\n" + "+\n" + "+/*\n" + " * This function splits huge page into normal pages. @page can point to any\n" + " * subpage of huge page to split. Split doesn't change the position of @page.\n" + " *\n" + "diff --git a/mm/memory.c b/mm/memory.c\n" + "index 93897f2..1589aa4 100644\n" + "--- a/mm/memory.c\n" + "+++ b/mm/memory.c\n" + "@@ -2340,6 +2340,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,\n" + " \t * not dirty accountable.\n" + " \t */\n" + " \tif (PageAnon(old_page) && !PageKsm(old_page)) {\n" + "+\t\tint total_mapcount;\n" + " \t\tif (!trylock_page(old_page)) {\n" + " \t\t\tget_page(old_page);\n" + " \t\t\tpte_unmap_unlock(page_table, ptl);\n" + "@@ -2354,13 +2355,17 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,\n" + " \t\t\t}\n" + " \t\t\tput_page(old_page);\n" + " \t\t}\n" + "-\t\tif (reuse_swap_page(old_page)) {\n" + "-\t\t\t/*\n" + "-\t\t\t * The page is all ours. Move it to our anon_vma so\n" + "-\t\t\t * the rmap code will not search our parent or siblings.\n" + "-\t\t\t * Protected against the rmap code by the page lock.\n" + "-\t\t\t */\n" + "-\t\t\tpage_move_anon_rmap(old_page, vma, address);\n" + "+\t\tif (reuse_swap_page(old_page, &total_mapcount)) {\n" + "+\t\t\tif (total_mapcount == 1) {\n" + "+\t\t\t\t/*\n" + "+\t\t\t\t * The page is all ours. Move it to\n" + "+\t\t\t\t * our anon_vma so the rmap code will\n" + "+\t\t\t\t * not search our parent or siblings.\n" + "+\t\t\t\t * Protected against the rmap code by\n" + "+\t\t\t\t * the page lock.\n" + "+\t\t\t\t */\n" + "+\t\t\t\tpage_move_anon_rmap(old_page, vma, address);\n" + "+\t\t\t}\n" + " \t\t\tunlock_page(old_page);\n" + " \t\t\treturn wp_page_reuse(mm, vma, address, page_table, ptl,\n" + " \t\t\t\t\t orig_pte, old_page, 0, 0);\n" + "@@ -2584,7 +2589,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,\n" + " \tinc_mm_counter_fast(mm, MM_ANONPAGES);\n" + " \tdec_mm_counter_fast(mm, MM_SWAPENTS);\n" + " \tpte = mk_pte(page, vma->vm_page_prot);\n" + "-\tif ((flags & FAULT_FLAG_WRITE) && reuse_swap_page(page)) {\n" + "+\tif ((flags & FAULT_FLAG_WRITE) && reuse_swap_page(page, NULL)) {\n" + " \t\tpte = maybe_mkwrite(pte_mkdirty(pte), vma);\n" + " \t\tflags &= ~FAULT_FLAG_WRITE;\n" + " \t\tret |= VM_FAULT_WRITE;\n" + "diff --git a/mm/swapfile.c b/mm/swapfile.c\n" + "index 83874ec..031713ab 100644\n" + "--- a/mm/swapfile.c\n" + "+++ b/mm/swapfile.c\n" + "@@ -922,18 +922,19 @@ out:\n" + " * to it. And as a side-effect, free up its swap: because the old content\n" + " * on disk will never be read, and seeking back there to write new content\n" + " * later would only waste time away from clustering.\n" + "+ *\n" + "+ * NOTE: total_mapcount should not be relied upon by the caller if\n" + "+ * reuse_swap_page() returns false, but it may be always overwritten\n" + "+ * (see the other implementation for CONFIG_SWAP=n).\n" + " */\n" + "-int reuse_swap_page(struct page *page)\n" + "+bool reuse_swap_page(struct page *page, int *total_mapcount)\n" + " {\n" + " \tint count;\n" + " \n" + " \tVM_BUG_ON_PAGE(!PageLocked(page), page);\n" + " \tif (unlikely(PageKsm(page)))\n" + "-\t\treturn 0;\n" + "-\t/* The page is part of THP and cannot be reused */\n" + "-\tif (PageTransCompound(page))\n" + "-\t\treturn 0;\n" + "-\tcount = page_mapcount(page);\n" + "+\t\treturn false;\n" + "+\tcount = page_trans_huge_mapcount(page, total_mapcount);\n" + " \tif (count <= 1 && PageSwapCache(page)) {\n" + " \t\tcount += page_swapcount(page);\n" + " \t\tif (count == 1 && !PageWriteback(page)) {" -c6803c23be6eb042d30e084076c9891531e8d0107290caee20d736c476f38388 +8166d8ea158570ad04495eb89fc1cc20199463ef767c4177ead93e438f8d1d00
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.