diff options
Diffstat (limited to 'mm/huge_memory.c')
| -rw-r--r-- | mm/huge_memory.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 404acdcd0455..165ea46bf149 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
| @@ -755,6 +755,21 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, | |||
| 755 | spinlock_t *ptl; | 755 | spinlock_t *ptl; |
| 756 | 756 | ||
| 757 | ptl = pmd_lock(mm, pmd); | 757 | ptl = pmd_lock(mm, pmd); |
| 758 | if (!pmd_none(*pmd)) { | ||
| 759 | if (write) { | ||
| 760 | if (pmd_pfn(*pmd) != pfn_t_to_pfn(pfn)) { | ||
| 761 | WARN_ON_ONCE(!is_huge_zero_pmd(*pmd)); | ||
| 762 | goto out_unlock; | ||
| 763 | } | ||
| 764 | entry = pmd_mkyoung(*pmd); | ||
| 765 | entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma); | ||
| 766 | if (pmdp_set_access_flags(vma, addr, pmd, entry, 1)) | ||
| 767 | update_mmu_cache_pmd(vma, addr, pmd); | ||
| 768 | } | ||
| 769 | |||
| 770 | goto out_unlock; | ||
| 771 | } | ||
| 772 | |||
| 758 | entry = pmd_mkhuge(pfn_t_pmd(pfn, prot)); | 773 | entry = pmd_mkhuge(pfn_t_pmd(pfn, prot)); |
| 759 | if (pfn_t_devmap(pfn)) | 774 | if (pfn_t_devmap(pfn)) |
| 760 | entry = pmd_mkdevmap(entry); | 775 | entry = pmd_mkdevmap(entry); |
| @@ -766,11 +781,16 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, | |||
| 766 | if (pgtable) { | 781 | if (pgtable) { |
| 767 | pgtable_trans_huge_deposit(mm, pmd, pgtable); | 782 | pgtable_trans_huge_deposit(mm, pmd, pgtable); |
| 768 | mm_inc_nr_ptes(mm); | 783 | mm_inc_nr_ptes(mm); |
| 784 | pgtable = NULL; | ||
| 769 | } | 785 | } |
| 770 | 786 | ||
| 771 | set_pmd_at(mm, addr, pmd, entry); | 787 | set_pmd_at(mm, addr, pmd, entry); |
| 772 | update_mmu_cache_pmd(vma, addr, pmd); | 788 | update_mmu_cache_pmd(vma, addr, pmd); |
| 789 | |||
| 790 | out_unlock: | ||
| 773 | spin_unlock(ptl); | 791 | spin_unlock(ptl); |
| 792 | if (pgtable) | ||
| 793 | pte_free(mm, pgtable); | ||
| 774 | } | 794 | } |
| 775 | 795 | ||
| 776 | vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, | 796 | vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, |
| @@ -821,6 +841,20 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr, | |||
| 821 | spinlock_t *ptl; | 841 | spinlock_t *ptl; |
| 822 | 842 | ||
| 823 | ptl = pud_lock(mm, pud); | 843 | ptl = pud_lock(mm, pud); |
| 844 | if (!pud_none(*pud)) { | ||
| 845 | if (write) { | ||
| 846 | if (pud_pfn(*pud) != pfn_t_to_pfn(pfn)) { | ||
| 847 | WARN_ON_ONCE(!is_huge_zero_pud(*pud)); | ||
| 848 | goto out_unlock; | ||
| 849 | } | ||
| 850 | entry = pud_mkyoung(*pud); | ||
| 851 | entry = maybe_pud_mkwrite(pud_mkdirty(entry), vma); | ||
| 852 | if (pudp_set_access_flags(vma, addr, pud, entry, 1)) | ||
| 853 | update_mmu_cache_pud(vma, addr, pud); | ||
| 854 | } | ||
| 855 | goto out_unlock; | ||
| 856 | } | ||
| 857 | |||
| 824 | entry = pud_mkhuge(pfn_t_pud(pfn, prot)); | 858 | entry = pud_mkhuge(pfn_t_pud(pfn, prot)); |
| 825 | if (pfn_t_devmap(pfn)) | 859 | if (pfn_t_devmap(pfn)) |
| 826 | entry = pud_mkdevmap(entry); | 860 | entry = pud_mkdevmap(entry); |
| @@ -830,6 +864,8 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr, | |||
| 830 | } | 864 | } |
| 831 | set_pud_at(mm, addr, pud, entry); | 865 | set_pud_at(mm, addr, pud, entry); |
| 832 | update_mmu_cache_pud(vma, addr, pud); | 866 | update_mmu_cache_pud(vma, addr, pud); |
| 867 | |||
| 868 | out_unlock: | ||
| 833 | spin_unlock(ptl); | 869 | spin_unlock(ptl); |
| 834 | } | 870 | } |
| 835 | 871 | ||
