]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - mm/huge_memory.c
Merge tag 'drm/tegra/for-5.1-rc5' of git://anongit.freedesktop.org/tegra/linux into...
[thirdparty/kernel/stable.git] / mm / huge_memory.c
index 404acdcd0455d0d3dda191d994dfb27d0359104e..165ea46bf14926a4ae1ee664631475e0150f185f 100644 (file)
@@ -755,6 +755,21 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
        spinlock_t *ptl;
 
        ptl = pmd_lock(mm, pmd);
+       if (!pmd_none(*pmd)) {
+               if (write) {
+                       if (pmd_pfn(*pmd) != pfn_t_to_pfn(pfn)) {
+                               WARN_ON_ONCE(!is_huge_zero_pmd(*pmd));
+                               goto out_unlock;
+                       }
+                       entry = pmd_mkyoung(*pmd);
+                       entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
+                       if (pmdp_set_access_flags(vma, addr, pmd, entry, 1))
+                               update_mmu_cache_pmd(vma, addr, pmd);
+               }
+
+               goto out_unlock;
+       }
+
        entry = pmd_mkhuge(pfn_t_pmd(pfn, prot));
        if (pfn_t_devmap(pfn))
                entry = pmd_mkdevmap(entry);
@@ -766,11 +781,16 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
        if (pgtable) {
                pgtable_trans_huge_deposit(mm, pmd, pgtable);
                mm_inc_nr_ptes(mm);
+               pgtable = NULL;
        }
 
        set_pmd_at(mm, addr, pmd, entry);
        update_mmu_cache_pmd(vma, addr, pmd);
+
+out_unlock:
        spin_unlock(ptl);
+       if (pgtable)
+               pte_free(mm, pgtable);
 }
 
 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,
        spinlock_t *ptl;
 
        ptl = pud_lock(mm, pud);
+       if (!pud_none(*pud)) {
+               if (write) {
+                       if (pud_pfn(*pud) != pfn_t_to_pfn(pfn)) {
+                               WARN_ON_ONCE(!is_huge_zero_pud(*pud));
+                               goto out_unlock;
+                       }
+                       entry = pud_mkyoung(*pud);
+                       entry = maybe_pud_mkwrite(pud_mkdirty(entry), vma);
+                       if (pudp_set_access_flags(vma, addr, pud, entry, 1))
+                               update_mmu_cache_pud(vma, addr, pud);
+               }
+               goto out_unlock;
+       }
+
        entry = pud_mkhuge(pfn_t_pud(pfn, prot));
        if (pfn_t_devmap(pfn))
                entry = pud_mkdevmap(entry);
@@ -830,6 +864,8 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
        }
        set_pud_at(mm, addr, pud, entry);
        update_mmu_cache_pud(vma, addr, pud);
+
+out_unlock:
        spin_unlock(ptl);
 }