diff options
Diffstat (limited to 'arch/i386/mm/pageattr.c')
| -rw-r--r-- | arch/i386/mm/pageattr.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c index d0cadb33b54c..92c3d9f0e731 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c | |||
| @@ -51,6 +51,13 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot, | |||
| 51 | if (!base) | 51 | if (!base) |
| 52 | return NULL; | 52 | return NULL; |
| 53 | 53 | ||
| 54 | /* | ||
| 55 | * page_private is used to track the number of entries in | ||
| 56 | * the page table page that have non standard attributes. | ||
| 57 | */ | ||
| 58 | SetPagePrivate(base); | ||
| 59 | page_private(base) = 0; | ||
| 60 | |||
| 54 | address = __pa(address); | 61 | address = __pa(address); |
| 55 | addr = address & LARGE_PAGE_MASK; | 62 | addr = address & LARGE_PAGE_MASK; |
| 56 | pbase = (pte_t *)page_address(base); | 63 | pbase = (pte_t *)page_address(base); |
| @@ -143,11 +150,12 @@ __change_page_attr(struct page *page, pgprot_t prot) | |||
| 143 | return -ENOMEM; | 150 | return -ENOMEM; |
| 144 | set_pmd_pte(kpte,address,mk_pte(split, ref_prot)); | 151 | set_pmd_pte(kpte,address,mk_pte(split, ref_prot)); |
| 145 | kpte_page = split; | 152 | kpte_page = split; |
| 146 | } | 153 | } |
| 147 | get_page(kpte_page); | 154 | page_private(kpte_page)++; |
| 148 | } else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { | 155 | } else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { |
| 149 | set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL)); | 156 | set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL)); |
| 150 | __put_page(kpte_page); | 157 | BUG_ON(page_private(kpte_page) == 0); |
| 158 | page_private(kpte_page)--; | ||
| 151 | } else | 159 | } else |
| 152 | BUG(); | 160 | BUG(); |
| 153 | 161 | ||
| @@ -157,10 +165,8 @@ __change_page_attr(struct page *page, pgprot_t prot) | |||
| 157 | * replace it with a largepage. | 165 | * replace it with a largepage. |
| 158 | */ | 166 | */ |
| 159 | if (!PageReserved(kpte_page)) { | 167 | if (!PageReserved(kpte_page)) { |
| 160 | /* memleak and potential failed 2M page regeneration */ | 168 | if (cpu_has_pse && (page_private(kpte_page) == 0)) { |
| 161 | BUG_ON(!page_count(kpte_page)); | 169 | ClearPagePrivate(kpte_page); |
| 162 | |||
| 163 | if (cpu_has_pse && (page_count(kpte_page) == 1)) { | ||
| 164 | list_add(&kpte_page->lru, &df_list); | 170 | list_add(&kpte_page->lru, &df_list); |
| 165 | revert_page(kpte_page, address); | 171 | revert_page(kpte_page, address); |
| 166 | } | 172 | } |
