tcp: enforce tcp_min_snd_mss in tcp_mtu_probing()
[pandora-kernel.git] / mm / huge_memory.c
index 4f0af97..1b04121 100644 (file)
@@ -997,6 +997,18 @@ out:
        return ret;
 }
 
+/*
+ * FOLL_FORCE can write to even unwritable pmd's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pmd(pmd_t pmd, struct page *page,
+                                       unsigned int flags)
+{
+       return pmd_write(pmd) ||
+               ((flags & FOLL_FORCE) && (flags & FOLL_COW) &&
+                page && PageAnon(page));
+}
+
 struct page *follow_trans_huge_pmd(struct mm_struct *mm,
                                   unsigned long addr,
                                   pmd_t *pmd,
@@ -1006,11 +1018,12 @@ struct page *follow_trans_huge_pmd(struct mm_struct *mm,
 
        assert_spin_locked(&mm->page_table_lock);
 
-       if (flags & FOLL_WRITE && !pmd_write(*pmd))
-               goto out;
-
        page = pmd_page(*pmd);
        VM_BUG_ON(!PageHead(page));
+
+       if (flags & FOLL_WRITE && !can_follow_write_pmd(*pmd, page, flags))
+               return NULL;
+
        if (flags & FOLL_TOUCH) {
                pmd_t _pmd;
                /*
@@ -1029,7 +1042,6 @@ struct page *follow_trans_huge_pmd(struct mm_struct *mm,
        if (flags & FOLL_GET)
                get_page_foll(page);
 
-out:
        return page;
 }
 
@@ -1827,14 +1839,14 @@ int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
                 * page fault if needed.
                 */
                return 0;
-       if (vma->vm_ops)
+       if (vma->vm_ops || (vm_flags & VM_NO_THP))
                /* khugepaged not yet working on file or special mappings */
                return 0;
        /*
         * If is_pfn_mapping() is true is_learn_pfn_mapping() must be
         * true too, verify it here.
         */
-       VM_BUG_ON(is_linear_pfn_mapping(vma) || vm_flags & VM_NO_THP);
+       VM_BUG_ON(is_linear_pfn_mapping(vma));
        hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
        hend = vma->vm_end & HPAGE_PMD_MASK;
        if (hstart < hend)
@@ -2009,6 +2021,24 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page,
        }
 }
 
+static bool hugepage_vma_check(struct vm_area_struct *vma)
+{
+       if ((!(vma->vm_flags & VM_HUGEPAGE) && !khugepaged_always()) ||
+           (vma->vm_flags & VM_NOHUGEPAGE))
+               return false;
+
+       if (!vma->anon_vma || vma->vm_ops)
+               return false;
+       if (is_vma_temporary_stack(vma))
+               return false;
+       /*
+        * If is_pfn_mapping() is true is_learn_pfn_mapping() must be
+        * true too, verify it here.
+        */
+       VM_BUG_ON(is_linear_pfn_mapping(vma));
+       return !(vma->vm_flags & VM_NO_THP);
+}
+
 static void collapse_huge_page(struct mm_struct *mm,
                               unsigned long address,
                               struct page **hpage,
@@ -2081,21 +2111,8 @@ static void collapse_huge_page(struct mm_struct *mm,
        hend = vma->vm_end & HPAGE_PMD_MASK;
        if (address < hstart || address + HPAGE_PMD_SIZE > hend)
                goto out;
-
-       if ((!(vma->vm_flags & VM_HUGEPAGE) && !khugepaged_always()) ||
-           (vma->vm_flags & VM_NOHUGEPAGE))
+       if (!hugepage_vma_check(vma))
                goto out;
-
-       if (!vma->anon_vma || vma->vm_ops)
-               goto out;
-       if (is_vma_temporary_stack(vma))
-               goto out;
-       /*
-        * If is_pfn_mapping() is true is_learn_pfn_mapping() must be
-        * true too, verify it here.
-        */
-       VM_BUG_ON(is_linear_pfn_mapping(vma) || vma->vm_flags & VM_NO_THP);
-
        pgd = pgd_offset(mm, address);
        if (!pgd_present(*pgd))
                goto out;
@@ -2325,25 +2342,11 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
                        progress++;
                        break;
                }
-
-               if ((!(vma->vm_flags & VM_HUGEPAGE) &&
-                    !khugepaged_always()) ||
-                   (vma->vm_flags & VM_NOHUGEPAGE)) {
-               skip:
+               if (!hugepage_vma_check(vma)) {
+skip:
                        progress++;
                        continue;
                }
-               if (!vma->anon_vma || vma->vm_ops)
-                       goto skip;
-               if (is_vma_temporary_stack(vma))
-                       goto skip;
-               /*
-                * If is_pfn_mapping() is true is_learn_pfn_mapping()
-                * must be true too, verify it here.
-                */
-               VM_BUG_ON(is_linear_pfn_mapping(vma) ||
-                         vma->vm_flags & VM_NO_THP);
-
                hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
                hend = vma->vm_end & HPAGE_PMD_MASK;
                if (hstart >= hend)