diff options
author | Vladimir Davydov <vdavydov@virtuozzo.com> | 2016-01-15 19:54:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-15 20:56:32 -0500 |
commit | 8749cfea11f3fffe8f7cad891470a77b36e0185f (patch) | |
tree | 1dc712f15e259ba4ff9c0ec62134440b28e89666 /mm/page_idle.c | |
parent | d965432234db94ee8e185f8fd8e3181bed7459fd (diff) |
mm: add page_check_address_transhuge() helper
page_referenced_one() and page_idle_clear_pte_refs_one() duplicate the
code for looking up pte of a (possibly transhuge) page. Move this code
to a new helper function, page_check_address_transhuge(), and make the
above mentioned functions use it.
This is just a cleanup, no functional changes are intended.
Signed-off-by: Vladimir Davydov <vdavydov@virtuozzo.com>
Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_idle.c')
-rw-r--r-- | mm/page_idle.c | 63 |
1 files changed, 9 insertions, 54 deletions
diff --git a/mm/page_idle.c b/mm/page_idle.c index 2c553ba969f8..4ea9c4ef5146 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c | |||
@@ -55,71 +55,26 @@ static int page_idle_clear_pte_refs_one(struct page *page, | |||
55 | unsigned long addr, void *arg) | 55 | unsigned long addr, void *arg) |
56 | { | 56 | { |
57 | struct mm_struct *mm = vma->vm_mm; | 57 | struct mm_struct *mm = vma->vm_mm; |
58 | spinlock_t *ptl; | ||
59 | pgd_t *pgd; | ||
60 | pud_t *pud; | ||
61 | pmd_t *pmd; | 58 | pmd_t *pmd; |
62 | pte_t *pte; | 59 | pte_t *pte; |
60 | spinlock_t *ptl; | ||
63 | bool referenced = false; | 61 | bool referenced = false; |
64 | 62 | ||
65 | pgd = pgd_offset(mm, addr); | 63 | if (!page_check_address_transhuge(page, mm, addr, &pmd, &pte, &ptl)) |
66 | if (!pgd_present(*pgd)) | ||
67 | return SWAP_AGAIN; | ||
68 | pud = pud_offset(pgd, addr); | ||
69 | if (!pud_present(*pud)) | ||
70 | return SWAP_AGAIN; | 64 | return SWAP_AGAIN; |
71 | pmd = pmd_offset(pud, addr); | ||
72 | |||
73 | if (pmd_trans_huge(*pmd)) { | ||
74 | ptl = pmd_lock(mm, pmd); | ||
75 | if (!pmd_present(*pmd)) | ||
76 | goto unlock_pmd; | ||
77 | if (unlikely(!pmd_trans_huge(*pmd))) { | ||
78 | spin_unlock(ptl); | ||
79 | goto map_pte; | ||
80 | } | ||
81 | |||
82 | if (pmd_page(*pmd) != page) | ||
83 | goto unlock_pmd; | ||
84 | 65 | ||
66 | if (pte) { | ||
67 | referenced = ptep_clear_young_notify(vma, addr, pte); | ||
68 | pte_unmap(pte); | ||
69 | } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { | ||
85 | referenced = pmdp_clear_young_notify(vma, addr, pmd); | 70 | referenced = pmdp_clear_young_notify(vma, addr, pmd); |
86 | spin_unlock(ptl); | ||
87 | goto found; | ||
88 | unlock_pmd: | ||
89 | spin_unlock(ptl); | ||
90 | return SWAP_AGAIN; | ||
91 | } else { | 71 | } else { |
92 | pmd_t pmde = *pmd; | 72 | /* unexpected pmd-mapped page? */ |
93 | 73 | WARN_ON_ONCE(1); | |
94 | barrier(); | ||
95 | if (!pmd_present(pmde) || pmd_trans_huge(pmde)) | ||
96 | return SWAP_AGAIN; | ||
97 | |||
98 | } | ||
99 | map_pte: | ||
100 | pte = pte_offset_map(pmd, addr); | ||
101 | if (!pte_present(*pte)) { | ||
102 | pte_unmap(pte); | ||
103 | return SWAP_AGAIN; | ||
104 | } | 74 | } |
105 | 75 | ||
106 | ptl = pte_lockptr(mm, pmd); | 76 | spin_unlock(ptl); |
107 | spin_lock(ptl); | ||
108 | |||
109 | if (!pte_present(*pte)) { | ||
110 | pte_unmap_unlock(pte, ptl); | ||
111 | return SWAP_AGAIN; | ||
112 | } | ||
113 | |||
114 | /* THP can be referenced by any subpage */ | ||
115 | if (pte_pfn(*pte) - page_to_pfn(page) >= hpage_nr_pages(page)) { | ||
116 | pte_unmap_unlock(pte, ptl); | ||
117 | return SWAP_AGAIN; | ||
118 | } | ||
119 | 77 | ||
120 | referenced = ptep_clear_young_notify(vma, addr, pte); | ||
121 | pte_unmap_unlock(pte, ptl); | ||
122 | found: | ||
123 | if (referenced) { | 78 | if (referenced) { |
124 | clear_page_idle(page); | 79 | clear_page_idle(page); |
125 | /* | 80 | /* |