|
@@ -1458,6 +1458,12 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Returns
|
|
|
+ * - 0 if PMD could not be locked
|
|
|
+ * - 1 if PMD was locked but protections unchange and TLB flush unnecessary
|
|
|
+ * - HPAGE_PMD_NR is protections changed and TLB flush necessary
|
|
|
+ */
|
|
|
int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
|
|
unsigned long addr, pgprot_t newprot, int prot_numa)
|
|
|
{
|
|
@@ -1466,9 +1472,11 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
|
|
|
|
|
if (__pmd_trans_huge_lock(pmd, vma) == 1) {
|
|
|
pmd_t entry;
|
|
|
- entry = pmdp_get_and_clear(mm, addr, pmd);
|
|
|
+ ret = 1;
|
|
|
if (!prot_numa) {
|
|
|
+ entry = pmdp_get_and_clear(mm, addr, pmd);
|
|
|
entry = pmd_modify(entry, newprot);
|
|
|
+ ret = HPAGE_PMD_NR;
|
|
|
BUG_ON(pmd_write(entry));
|
|
|
} else {
|
|
|
struct page *page = pmd_page(*pmd);
|
|
@@ -1476,12 +1484,17 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
|
|
/* only check non-shared pages */
|
|
|
if (page_mapcount(page) == 1 &&
|
|
|
!pmd_numa(*pmd)) {
|
|
|
+ entry = pmdp_get_and_clear(mm, addr, pmd);
|
|
|
entry = pmd_mknuma(entry);
|
|
|
+ ret = HPAGE_PMD_NR;
|
|
|
}
|
|
|
}
|
|
|
- set_pmd_at(mm, addr, pmd, entry);
|
|
|
+
|
|
|
+ /* Set PMD if cleared earlier */
|
|
|
+ if (ret == HPAGE_PMD_NR)
|
|
|
+ set_pmd_at(mm, addr, pmd, entry);
|
|
|
+
|
|
|
spin_unlock(&vma->vm_mm->page_table_lock);
|
|
|
- ret = 1;
|
|
|
}
|
|
|
|
|
|
return ret;
|